FAQ
Engine and Compatibility
Does Formulon require Excel?
No at runtime. Formulon does not automate Excel, COM, or a Microsoft runtime when it loads workbooks, evaluates formulas, recalculates, or saves files.
Excel is used during development and verification to capture oracle data: reference values returned by the real product. v0.9.2 also added Windows Excel bridge coverage for pivot tables and print pagination, but that is a test track, not a production dependency.
Which compatibility profile is the default?
The default profile is win-365-ja_JP, modelled on Excel 365 for Windows with the Japanese locale. Mac Excel 365 ja-JP is also tracked through oracle data. English-locale profiles are not exposed until matching oracle data exists. See Locale profiles.
How many Excel functions can it run?
Formulon recognizes 522 Excel function names. 505 / 522 are real local implementations in the calculation engine.
The remaining 17 are 2 environment-bound functions (CELL, INFO) and 15 unavailable service / connection stubs: COPILOT, PY, IMAGE, RTD, STOCKHISTORY, WEBSERVICE, TRANSLATE, DETECTLANGUAGE, and the CUBE functions. These names are recognized, but they are not local implementations. See Formula coverage.
Can it execute COPILOT, PY, STOCKHISTORY, or WEBSERVICE?
No. Those functions require Microsoft 365 cloud services, the hosted Python runtime, market data services, HTTP I/O, or OLAP connections outside Formulon.
Formulon recognizes the names so workbooks fail in a predictable, Excel-shaped way instead of falling through as unknown parser names. It does not embed or proxy those external services.
Do results exactly match Excel?
Formulon checks behavior against Excel oracle data per profile, such as win-365-ja_JP. That is not a blanket guarantee for every workbook. Locale behavior, volatile functions, external-service dependencies, file structures, and undocumented Excel details can still produce differences.
- Excel (reference)
- captured oracle data
- profile (win-365-ja_JP)
- divergence.yaml
- Formulon output
Real Excel is the reference. Its observed behavior is captured as oracle data, organized under a named profile such as win-365-ja_JP, and any accepted difference from that reference is recorded in divergence.yaml with a reason and last-verified Excel build — rather than left as an unexplained mismatch in Formulon's output. See Oracle testing for the full pipeline.
For business-critical workbooks, pin the Formulon version and profile, and keep representative workbook fixtures.
Is this trying to clone all of Excel?
No. Formulon is a headless calculation and workbook-processing engine. It intentionally does not clone Excel's desktop UI, chart renderer, VBA runtime, PowerQuery engine, external-data refresh pipeline, or legacy .xls stack.
The goal is narrower: load modern workbook files, evaluate local spreadsheet formulas, preserve workbook structures where practical, and expose the same core through WASM, Python, CLI, Native Node, and MCP.
Why not just use Excel, LibreOffice, HyperFormula, or a cloud spreadsheet API?
Use those when they fit. Excel is the right answer when you need the real application, VBA, PowerQuery, live connections, or final visual review. LibreOffice is a broad office suite and can be a good batch conversion tool. HyperFormula is useful when you want an embeddable formula engine without full .xlsx workbook round-trip semantics. Cloud spreadsheet APIs are useful when the workbook already lives in that product.
Formulon exists for a different slot: applications that need local, embeddable .xlsx calculation and workbook mutation without automating a desktop app or sending workbook data to a hosted spreadsheet service.
Isn't Excel compatibility basically impossible?
Unqualified Excel compatibility is too broad to be useful. Formulon avoids that claim. It targets named profiles, records observed Excel results as oracle data, and documents accepted divergences.
That still leaves hard cases: volatile functions, undocumented coercions, locale-sensitive formatting, floating-point edges, external services, and file features that are preserved but not semantically evaluated. Compatibility should be validated against the actual workbook set you plan to run.
Why is the default profile Japanese Excel?
The first checked-in formula oracle was captured on Mac Excel 365 ja-JP; win-365-ja_JP is the runtime default and is verified through variant goldens (and is the primary profile for the separate pivot/print workbook-oracle data added in v0.9.2 via the Windows COM bridge). Locale affects real spreadsheet behavior: function names, separators, date parsing, text formatting, collation, and error surfaces can differ.
English-locale profiles are intentionally not exposed until matching oracle data exists. That is a coverage gap, not a claim that Japanese Excel is globally representative.
Files and Workbook Features
Which file formats are supported?
The normal public API path is .xlsx bytes. The WASM, Python, Native Node, CLI, and MCP surfaces are primarily designed to load .xlsx, recalculate, and save .xlsx.
.xlsb (MS-XLSB) is also read and written. As of v0.9.3, styles, cross-sheet 3-D references, workbook-scope defined names (including LET and future-function names), and dynamic-array spill formulas all round-trip through .xlsb. Conditional formatting, pivot tables, comments, and data validation are still OOXML-only, and array-constant literals in .xlsb are limited to numeric elements. The CLI and saveEx / save_ex APIs pick the format from the output extension (-o file.xlsb writes MS-XLSB) and sniff the input format by content rather than extension.
Macro-enabled OOXML packages such as .xlsm / .xltm have tests for preserving vbaProject.bin byte-for-byte, but VBA is never executed. Legacy .xls / BIFF is out of scope.
Does it execute VBA?
No. VBA projects can be preserved through a read / write round-trip, but macros are never executed. Workbooks that rely on macro-side state may differ from Excel.
Does it support PowerQuery, DAX, or live external connections?
No. PowerQuery, DAX, live external connections, Web / OData / OLAP refresh, and similar data-refresh systems are outside Formulon. Refresh data upstream, then pass the resulting .xlsx to Formulon.
What about pivot tables?
Pivot cache and PivotTable structure preservation, pivot operations, and pivot layout inspection are implemented, with full parity across the C API, Node addon, WASM, and Python bindings since v0.9.3. v0.9.2 added workbook oracle coverage for pivot tables through the Windows Excel bridge.
Formulon is not a replacement for Excel's external-data refresh and pivot-cache rebuild pipeline.
Are print settings and page breaks preserved?
.xlsx page setup, margins, header/footer, print options, printer settings, and page-break metadata are part of the round-trip surface. v0.9.2 added print pagination oracle coverage and improved tracking for margins and Page Break Preview behavior.
Formulon is not a print-preview UI or PDF renderer. Final page rendering belongs to Excel or another rendering layer.
Does Formulon include a spreadsheet UI?
The Formulon engine is headless. Grid rendering and interactive spreadsheet UI are not part of the core engine.
@libraz/formulon-cell and its framework wrappers are public reference UI libraries for browser integration testing. They are useful examples of wiring the engine to a workbook-like surface, but they are not complete Excel-compatible UI products: feature coverage is partial, UI/UX intentionally does not mirror Excel exactly, and UI bugs may remain.
Can I safely run arbitrary .xlsx files from users?
Do not treat arbitrary spreadsheet files as harmless. Formulon does not execute VBA, PowerQuery, external connections, or HTTP-backed formula functions, which removes several common execution paths. It still parses complex ZIP/XML workbook data and may read or write files depending on the surface you use.
For untrusted uploads, run Formulon in a sandboxed process or worker, set file-size and time limits, restrict filesystem access, and keep the package version pinned and updated.
Are charts, shapes, images, and formatting recalculated?
Formatting and many workbook structures can be read, written, or preserved, but preservation is not the same as rendering or semantic evaluation. Formulon does not render charts, draw shapes, produce print-perfect PDFs, or execute image-fetching behavior from IMAGE.
Use Excel or a rendering layer for visual review. Use Formulon for calculation and workbook mutation.
Runtimes and Packages
Why is the core C++17?
C++17 is a conservative portability choice for this project. It runs predictably through Emscripten / WASM, can be packaged for npm, PyPI, CLI, and native embedding, and keeps the compiler baseline broad enough for GCC 9+ and Clang 10+ environments.
The implementation also uses a deliberately small C++ subset: C ABI boundaries, explicit error values, limited template use, controlled inlining, and translation-unit-level size tracking. That makes code size and generated artifacts easier to reason about across the supported distribution targets. It also reuses the author's existing C++ conventions: C++17, Expected<T, Error>, no exceptions / RTTI, and Google-style formatting.
Why not Rust?
Aware of the trade-off. Rust would be a reasonable language for parts of this problem, and the memory-safety argument is real. Formulon is built around existing C / C++ infrastructure: OOXML parsing, ZIP handling, regular expressions, numeric conversion, C ABI packaging, Emscripten, and native embedding. Using C++ keeps that stack direct instead of adding FFI layers around libraries such as miniz, pugixml, PCRE2, and double-conversion.
The main compatibility risk is also not only memory safety. The hard part is Excel behavior: coercion rules, error propagation, locale handling, dates, dynamic arrays, OOXML round-trips, and oracle drift. Rust can help with many implementation risks, but it does not remove the spreadsheet-specification work. Formulon's current C++17 conventions, C ABI boundary, formatter, and oracle / CTest gates are the path the project is built around. Not a recommendation for everyone else to start new spreadsheet engines in C++.
Which runtime should I pick?
Pick by deployment target:
| Use case | Recommended surface |
|---|---|
| Browser calculation | @libraz/formulon (WASM) |
| Browser or no-native-addon Node.js | @libraz/formulon (WASM) |
| Native Node execution from a source checkout | packages/npm-native |
| Python batches or notebooks | formulon on PyPI |
| Shell or CI jobs | CLI from GitHub Releases |
| AI-agent workbook editing | @libraz/formulon-mcp |
See Choose a surface.
Does the Python wheel require Cython, NumPy, or pybind11?
No. The formulon wheel is py3-none-any and ships formulon_capi.wasm plus a pure-Python wrapper. wasmtime is the runtime dependency. Python 3.9 or newer is required.
Does Native Node expose the full WASM API?
Yes for the Workbook shape. The source-tree Native Node package under packages/npm-native exposes the same 174 Workbook instance methods plus the three static factories (createDefault / createEmpty / loadBytes) as the WASM-backed package, including the v0.9.4 evaluateFormulaText / evaluateConditionalFormula / getComments additions. WASM additionally exposes a delete() lifecycle method, since it has no host garbage collector to free the underlying engine instance. Result envelopes and value shapes are otherwise the same.
Choose Native Node when you build or stage the source-tree package and can deploy a platform-specific .node binary. It is useful for native threads and fewer heap copies on loadBytes / save. Choose WASM for browsers or Node deployments that cannot ship native addons.
Does it work offline?
Local calculation works offline. WASM, Python, Native Node, and CLI process the formula or workbook bytes locally.
Service-backed functions such as WEBSERVICE, STOCKHISTORY, TRANSLATE, and COPILOT do not execute in Formulon, online or offline.
Is workbook data sent anywhere?
The core engine processes workbook bytes locally. The WASM, Python, Native Node, and CLI surfaces do not need a Formulon-hosted service for calculation.
Your host application can still send files elsewhere if you build it that way. MCP deployments also depend on the client and filesystem permissions you grant to the agent.
Do browser deployments need COOP / COEP?
Yes for the pthread-backed WASM path. Browsers require SharedArrayBuffer, which normally means serving with:
Cross-Origin-Opener-Policy: same-origin
Cross-Origin-Embedder-Policy: require-corpWithout those headers, @libraz/formulon (the raw WASM package) has no fallback: createFormulon() hard-fails. formulon-cell's WorkbookHandle.createDefault() also rejects by default when SharedArrayBuffer is unavailable; the in-memory stub engine only runs if the host opts in with preferStub: true. Use wb.isStub / isUsingStub() to detect the stub at runtime, and handle the rejection with onError or a try/catch around createDefault() instead of assuming a silent fallback.
Are Vite warnings about node:module or node:worker_threads a problem?
Usually no. The @libraz/formulon WASM factory contains a Node runtime branch, so browser bundlers can warn that Node modules were externalized. That branch is dead code in browsers.
If the build fails rather than only warning, use ES module workers and an es2022 or newer build target. See Troubleshooting.
Use Cases
What is Formulon good for?
It fits systems that treat Excel workbooks as part of an application or workflow: browser quote tools, server-side report calculation, CI checks for workbook result drift, Python batch jobs, and AI-agent workbook editing.
It is not a desktop Excel replacement, a VBA runtime, a PowerQuery / DAX engine, or a live external-data refresh platform. See Scenarios.
Is it fast?
There is no single honest benchmark number for spreadsheets. Runtime depends on workbook shape, formula mix, dynamic arrays, shared formulas, file size, and whether you are measuring parse time, recalculation, save time, or host-language overhead.
The practical claim is architectural: the runtimes share one native C++ core, and WASM / Python / CLI / Native Node are packaging surfaces around that core. Benchmark your representative workbooks before making latency or cost commitments.
Is Formulon production-ready?
It is pre-1.0. The local formula engine is broad, but APIs and packaging may still change. For business-critical use, pin the Formulon version, pin the target profile, and keep representative workbook fixtures.
The strongest production fit is controlled workbooks in server jobs, CI, internal tools, and embedded calculation. Do not treat it as a universal drop-in replacement for arbitrary Excel files.
What breaks most often in real integrations?
The common failures are not usually simple arithmetic. They are unsupported external data refresh, accidental reliance on macros, locale-specific parsing, volatile functions, hidden workbook state, unsupported file structures, and assuming that preserved visual objects were rendered or recomputed.
Start with a small set of representative workbooks, dump the formulas, compare outputs against the target Excel profile, and keep those files in CI.
Is this legally tied to Microsoft Excel?
No Microsoft runtime, service, SDK, or product license is required by Formulon at runtime. Excel is used as a reference implementation during development to capture oracle data.
Excel is Microsoft's product and trademark. Formulon is an independent Apache-2.0 project and does not claim to be Microsoft Excel or a Microsoft-sponsored implementation.
AI / MCP
What is formulon-mcp?
@libraz/formulon-mcp is a stdio MCP server exposing Formulon workbook operations to AI agents. It provides 31 tools for opening .xlsx files, inspecting workbook structure, editing cells and sheets, recalculating, and saving. Node.js 22 or newer is required.
npx -y @libraz/formulon-mcpSee MCP.
Can agents execute arbitrary code through it?
No. The MCP server validates inputs and isolates sessions by sessionId. The low-level formulon_workbook_call tool only dispatches Workbook methods listed in the allowlist in formulon-mcp's src/sessions.ts.
The MCP server can still read and write files, so production use should control the client permissions, working directory, and allowed file scope.
Recent Releases
What changed in v0.9.5 for users?
v0.9.5 adds ad-hoc array evaluation. evaluateFormulaArray (Node addon, WASM, C API) and evaluate_formula_array (Python) evaluate a dynamic-array / spilled formula against a loaded workbook and return the whole Array result (EvalArrayResult) instead of reducing to the top-left element the way v0.9.4's evaluateFormulaText does. It keeps the same read-only, no-mutation, and self-reference caveats. Note the Python asymmetry: Python now has the whole-array variant and merge_function_metadata, but the scalar evaluate_formula_text / evaluate_conditional_formula remain Node addon / WASM / C-API only.
It also adds a function-metadata provider seam: mergeFunctionMetadata (Node) / merge_function_metadata (Python) is a pure helper that merges host-supplied localized function metadata (signature / description / localized name) over the engine's structural catalog, with precedence locale-override then entry-default then engine-value. functionMetadata now also recognizes lazy-dispatch forms (XLOOKUP, SUMIFS, …) and parser special forms (LET, LAMBDA), and reports unbounded arity as null / None.
Two evaluation fixes: range-shaped defined names (e.g. Sheet1!$A$1:$A$5) now evaluate as an Array instead of collapsing to a scalar via implicit intersection, and spill-phantom cells are fully enumerated (cell_count / cell_at fidelity).
What changed in v0.9.4 for users?
v0.9.4 adds read-only ad-hoc formula evaluation on existing workbooks, on the C API, Node addon, and WASM surfaces (Python has no equivalent yet). evaluateFormulaText and evaluateConditionalFormula let hosts ask "what would this formula return here?" without writing a formula into a cell first. Evaluation is strictly read-only: it does not mutate the workbook or join the dependency graph, and array/spill results are reduced to their top-left element rather than returned as a range — see Dynamic arrays for what that element selection means in practice. They resolve workbook references and names, and the conditional-format path applies the relative-reference and predicate rules expected by Excel-style CF evaluation.
It also adds comment enumeration (getComments on Node addon; fm_sheet_get_comment_count / fm_sheet_get_comment_at_index on the C API) for sheets, round-trips data-validation dropdown visibility with Excel's inverted showDropDown OOXML semantics handled for callers, and makes conditional-format rule creation (addConditionalFormat / fm_sheet_cf_add_rule) return the new rule's index. Conditional-format rule creation returns the new rule's index on every binding, Python included. Comment enumeration lands on the C API, Node addon, and WASM; the Python binding does not expose it yet.
What changed in v0.9.3 for users?
v0.9.3 closed most of the remaining gaps between surfaces and file formats:
- Full binding-surface parity across the C API, Node addon, WASM, and Python: pivot-cache worksheet source/layout, sheet-view display/orientation flags,
save_ex(explicit XLSX/XLSB selection), sheet-scoped defined names, and conditional-formatColorScale/DataBar/IconSetpayloads are now available identically on every binding. - Conditional formatting gained whole-row/whole-column
sqrefsupport and x14 data-bar overlay decoding (gradient, axis position, negative fill/border). - XLSB protocol gaps closed: styles, workbook-scope defined names (including
LETand future-function names), cross-sheet 3-D references, and dynamic-array spill formulas now round-trip through.xlsb— several of these previously produced files real Excel could not open. - OOXML round-trip fidelity:
workbookPr/bookViews/workbookProtection,date1904, table style info, and per-cell theme/indexed color specs all survive a load-modify-save cycle on real Excel-authored workbooks.
See the file format support matrix for the current per-format detail.
What changed in v0.9.2 for users?
The main visible changes are the clear split between 522 recognized function names and 505 local implementations, workbook oracle coverage for pivot tables and print pagination through the Windows Excel bridge, and several Excel-alignment fixes.
Formula changes include Excel-style 15-significant-digit numeric literal parsing, ARRAYTOTEXT scalar error propagation, PIVOTBY layout fixes, and fixes around MAP / MAKEARRAY, FREQUENCY, WRAPROWS / WRAPCOLS, TRIMRANGE, and PERCENTILE.EXC.
File-format changes include stronger preservation for unknown workbook relationships, shared-formula references, print pagination metadata, margins, and Page Break Preview-derived information.
License
How is Formulon licensed?
formulon, formulon-cell, and formulon-mcp are Apache-2.0. You may use, modify, and redistribute them under the license terms.