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 compare text case-insensitively by bytes, because Windows ordering is not measured. The profile is not saved into the file, so store the id your application targets and apply it again after loading.

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