XLSX formula recalculation in Node.js
May 29, 2026 ยท View on GitHub
This page is for the backend workflow where an .xlsx file is not just a
report artifact. The service imports a workbook, edits input cells, needs the
new formula values immediately, and still has to export an .xlsx at the end.
That is different from simply writing formula strings into a file and waiting for Excel to calculate later.
The production shape
A realistic server-side loop looks like this:
- Load or generate a pricing, payout, quote, or validation workbook.
- Pass the bytes to
@bilig/xlsx-formula-recalc. - Write request inputs into known cells.
- Read the recalculated formula outputs before returning a response.
- Export the edited workbook back to
.xlsx. - Reimport the exported workbook in a test and verify formulas still produce the same values.
The last step matters. It catches the difference between "the in-memory model looked right" and "the workbook artifact still works after the XLSX boundary."
Install the narrow package
npm install @bilig/xlsx-formula-recalc
For a one-off CLI run without adding it to a project:
npx --package @bilig/xlsx-formula-recalc xlsx-recalc --demo --json
The demo creates a tiny workbook, edits input cells, recalculates Summary!B2,
writes bilig-formula-recalc-demo.xlsx, and prints
recalculationCompleted: true, expectedValueMatched: true, and
excelParity: "not_proven".
For an existing workbook:
npx --package @bilig/xlsx-formula-recalc xlsx-recalc pricing.xlsx \
--set Inputs!B2=48 \
--set Inputs!B3=1500 \
--read Summary!B7 \
--out pricing.recalculated.xlsx \
--json
The CLI writes the updated workbook and prints the values read after
recalculation. Cell targets are sheet-qualified A1 references such as
Inputs!B2 or 'Pricing Model'!F12.
If you do not know the output cells yet, inspect the workbook first:
npx --package @bilig/xlsx-formula-recalc xlsx-recalc pricing.xlsx --inspect --json
Inspection does not write an output workbook. It lists formula cells, reports
stale cached values, and suggests --read targets so the next command proves
the cells your service actually depends on.
Run the maintained example
If you want the shortest proof without cloning the repo, run the
curlable XLSX recalculation proof. It creates
source and edited .xlsx files in a blank folder and verifies the round trip.
From a clean clone:
git clone https://github.com/proompteng/bilig.git
cd bilig/examples/xlsx-recalculation-node
npm install
npm start
The example builds a pricing workbook, exports pricing-model-source.xlsx,
passes it through @bilig/xlsx-formula-recalc, changes input cells, reads a
recalculated approval decision, exports pricing-model-edited.xlsx, and
reimports the edited workbook.
Expected output includes:
{
"before": {
"decision": "review"
},
"after": {
"decision": "approved"
},
"checks": {
"decisionChanged": true,
"exportedReimportMatchesAfter": true,
"formulasSurvivedXlsxRoundTrip": true,
"verified": true
}
}
The source is intentionally small enough to read in one sitting:
examples/xlsx-recalculation-node/recalculate-xlsx.ts.
Minimal API boundary
Use the package API at the file boundary when the service needs a recalculated answer immediately:
import { readFile, writeFile } from 'node:fs/promises'
import { recalculateXlsx } from '@bilig/xlsx-formula-recalc'
const result = recalculateXlsx(await readFile('pricing-model-source.xlsx'), {
fileName: 'pricing-model-source.xlsx',
edits: [
{ target: 'Inputs!B2', value: 48 },
{ target: 'Inputs!B3', value: 1250 },
],
reads: ['Summary!B7'],
})
await writeFile('pricing-model-edited.xlsx', result.xlsx)
console.log({ decision: result.reads['Summary!B7'], warnings: result.warnings })
In production, keep a narrow adapter around this boundary. Your application should know exactly which cells are inputs, which cells are outputs, and which checks prove the workbook is still valid after export.
When to keep using ExcelJS or SheetJS
Use ExcelJS or SheetJS first when the job is workbook-file manipulation: styling, rows, sheets, images, tables, streaming writes, or broad spreadsheet format interchange.
Use @bilig/xlsx-formula-recalc when the Node process must own the recalculated answer
before it accepts, rejects, queues, or persists a workflow. Use
@bilig/headless/xlsx directly only when you need the lower-level WorkPaper
snapshot boundary.
Many services should combine the tools: use a file library for presentation details and use a formula runtime for the auditable decision path.
Trust checks before production
Before putting XLSX recalculation on a customer-critical path, add tests for:
- the exact input cells your service writes
- the exact output cells your service reads
- unsupported formulas and compatibility limits
- exported workbook reimport
- stale cached values in source files
- a golden workbook fixture that opens in Excel or another spreadsheet app
Bilig is not full Excel. The useful promise is narrower: a Node service can run formula-backed workbook logic, prove readback after edits, and keep a checked XLSX boundary around the parts it owns.
Related proof
- Curlable XLSX recalculation proof
- External workbook recalculation proof
- Runnable XLSX recalculation example
- Excel file as a calculation engine in Node.js
- Stale XLSX formula cache in Node.js
- ExcelJS formula recalculation in Node.js
- ExcelJS shared formulas and Node.js recalculation
- SheetJS and ExcelJS boundary
- Stale XLSX cache and Excel oracle checks
- Compatibility limits
After the proof
If verified: true matches your Node/XLSX workflow, star the repository or
bookmark Bilig so the recalculation path is easy to find again:
https://github.com/proompteng/bilig/stargazers.
Watch releases if this is close to a production dependency: https://github.com/proompteng/bilig/subscription.
If a real workbook is close but blocked by a formula, external-link, import, export, or round-trip edge case, open the smallest adoption blocker you can share: https://github.com/proompteng/bilig/discussions/new?category=general.