Skip to content
librazPublic

About

Excel 365 calculation engine in C++17: evaluate formulas and recalculate .xlsx / .xlsb workbooks without Excel. Ships as WASM (browser / Node), a Python package, and a native CLI.

Topics

Resources

Contributing

Security policy

Stars

5 stars

Watchers

1 watching

Forks

Repository files navigation

Formulon

CI npm PyPI codecov License C++17 Platform Docs

Formulon recalculates Excel workbooks and formulas without Excel, with results checked against real Excel 365. No Excel install, no Windows, no COM automation: one C++17 core ships as WebAssembly for browsers and Node, as a Python package, and as native CLI binaries, so a workbook gives the same values wherever it runs.

Use it when you need to:

  • Recalculate workbooks on a server — load .xlsx or .xlsb in a batch job, CI run or data pipeline, change inputs, and save it with fresh values.
  • Run spreadsheet logic in the browser — evaluate formulas and whole workbooks client-side, so uploaded files never leave the user's machine.
  • Keep the model in Excel — call the workbook your team already maintains from Node or Python instead of re-implementing its formulas.
  • Get the answer Excel gives in a given locale — Japanese byte counting, German decimal commas and localized TRUE / FALSE follow the profile you pick.
  • Give AI agents spreadsheet tools — formulon-mcp exposes the engine over MCP.

Known differences from Excel are listed case by case in tests/divergence.yaml, each with a reason and the Excel build it was last verified on.

📖 Documentation  ·  Getting started  ·  Locale profiles  ·  Formula coverage  ·  API

What's inside

  • Formula engine — 526 Excel function names, 511 implemented locally; dynamic arrays, LET / LAMBDA, and REGEX*. The rest call cloud or COM services and return a fixed error. Coverage
  • Workbook I/O — read, recalculate and write .xlsx and .xlsb, including styles, conditional formatting, tables, pivot tables and print layout. File formats
  • Locale profiles — 28 Excel behavior profiles across fourteen locales on Mac and Windows hosts. Locale profiles
  • Excel oracle — formula results are compared bit for bit against goldens captured from Mac Excel 365 in fourteen locales; pivot and print layout against Windows Excel 365. Oracle testing
  • Size-budgeted WASM — CI fails the build above 3.75 MiB uncompressed or 1056 KiB Brotli. Size budgets

Installation

npm install @libraz/formulon   # browsers and Node 22+
pip install formulon            # Python 3.9+

CLI binaries for darwin-arm64, linux-x64 and linux-arm64 are on GitHub Releases.

Quick start

import createFormulon from '@libraz/formulon';

const Module = await createFormulon();
console.log(Module.evalFormula('=SUM(1,2,3)').value.number); // 6
import formulon

print(formulon.eval_formula("=SUM(1,2,3)").to_python())  # 6.0
formulon eval '=SUM(1,2,3)'
formulon recalc input.xlsx -o output.xlsx

Loading, editing and saving workbooks are covered in Recalculate a workbook.

Switching locale profiles

New workbooks use win-365-en_US. Formulas are always written with English function names and the stored separators; the profile decides how text is parsed and how results are rendered. Switch it per workbook and recalculate:

const wb = Module.Workbook.createDefault();
try {
  wb.setFormula(0, 0, 0, '=LENB("日本")');  // A1
  wb.setFormula(0, 1, 0, '=VALUE("1,5")');  // A2
  wb.setFormula(0, 2, 0, '=ISEVEN(2)');     // A3

  for (const id of ['mac-365-en_US', 'mac-365-ja_JP', 'mac-365-de_DE']) {
    wb.setExcelProfileId(id);
    wb.recalc(); // a profile change marks formulas dirty
    console.log(id, [0, 1, 2].map((row) => wb.getDisplayText(0, row, 0).text));
  }
} finally {
  wb.delete();
}
// mac-365-en_US [ '2', '#VALUE!', 'TRUE' ]
// mac-365-ja_JP [ '4', '#VALUE!', 'TRUE' ]
// mac-365-de_DE [ '2', '1,5', 'WAHR' ]
with formulon.Workbook.create_default() as wb:
    wb.set_formula(0, 0, 0, '=LENB("日本")')
    wb.set_formula(0, 1, 0, '=VALUE("1,5")')
    wb.set_formula(0, 2, 0, "=ISEVEN(2)")

    for profile in ("mac-365-en_US", "mac-365-ja_JP", "mac-365-de_DE"):
        wb.set_excel_profile_id(profile)
        wb.recalc()
        print(profile, [wb.get_display_text(0, row, 0)[0] for row in range(3)])

The ids are {mac,win}-365-{ja_JP,en_US,de_DE,fr_FR,zh_CN,ko_KR,th_TH,es_ES,es_MX,pt_BR,ru_RU,zh_TW,it_IT,nl_NL}. Every mac-* profile and win-365-ja_JP is measured against Excel; the other win-* profiles are estimated from the Mac measurements. On a mac-* profile, text comparison, sorting, lookups and grouping follow that locale's measured Mac Excel collation; win-* profiles add the Windows word-sort rules measured on Windows Excel 365 ja-JP to that locale's collation. The profile is not saved into the file, so store the id your application targets and apply it again after loading.

For a new workbook that matches what Excel creates in a locale, use Workbook.createForProfile(id) (Workbook.create_for_profile in Python) instead of createDefault: it selects the profile and also sets the body and phonetic fonts, the localized Normal style and first sheet names, and the page margins Excel uses there.

Non-goals

VBA execution, legacy .xls, chart rendering, Power Query / DAX, pivot cache refresh from source data, live external connections, and a spreadsheet UI are permanently out of scope. See Non-goals.

Contributing

The most useful contribution is Excel oracle data from your locale, especially from Windows Excel 365: make oracle-contribute drives Excel and captures goldens. See CONTRIBUTING.md and Oracle contribution.

License

Apache License 2.0. See also NOTICE.

Related projects

  • formulon-cell — browser spreadsheet UI built on @libraz/formulon
  • formulon-mcp — MCP server that gives AI agents workbook tools

About

Excel 365 calculation engine in C++17: evaluate formulas and recalculate .xlsx / .xlsb workbooks without Excel. Ships as WASM (browser / Node), a Python package, and a native CLI.

Topics

Resources

Contributing

Security policy

Stars

5 stars

Watchers

1 watching

Forks

Releases

Packages

Contributors

Languages