bilig

XLSX formula support answers for Node.js

Use these when someone has the exact stale-formula problem. Do not paste them into old threads just to mention Bilig. If you answer publicly, disclose that you maintain Bilig and make the reply useful without a star ask.

The shared point is simple: SheetJS, ExcelJS, xlsx-populate, and template libraries can write workbook bytes. They do not automatically make cached formula values fresh inside the same Node process.

SheetJS or xlsx

Useful when the question is: “I changed an input with SheetJS, why is the formula result still old?”

Answer shape:

SheetJS is doing the file I/O part. The stale value is the cached formula result
stored in the XLSX file; editing an input cell does not recalculate that cache
inside Node.

If Excel or LibreOffice will open the file before anyone trusts the number,
set recalc-on-open and stop there. If the backend needs the value now, add a
calculation/readback step before you read the formula cell.

Minimal local check:

npx --yes --package @bilig/sheetjs-formula-recalc sheetjs-recalc --demo --json

For a real file:

npx --package @bilig/sheetjs-formula-recalc sheetjs-recalc quote.xlsx \
  --set Inputs!B2=48 \
  --read Summary!B7 \
  --out quote.recalculated.xlsx \
  --json

I maintain Bilig, so treat this as one option, not the only answer. xlsx-calc,
HyperFormula, Excel, LibreOffice, or Microsoft Graph can also be the right
boundary depending on formula coverage and how exact you need Excel behavior to
be.

Owned docs:

ExcelJS

Useful when the question is: “How do I get the computed value after writing formula inputs with ExcelJS?”

Answer shape:

ExcelJS can write formulas and cached results, but it does not recalculate the
dependency graph after your service changes an input. `fullCalcOnLoad` helps
the next spreadsheet app that opens the file; it does not give the current
Node process a fresh formula value.

If the product is just a report someone opens later, ExcelJS is enough. If the
API/job/test needs the computed value now, bridge the workbook through a
runtime before reading the formula cell.

One-command check:

npx --yes --package @bilig/exceljs-formula-recalc exceljs-recalc --demo --json

That keeps ExcelJS as the workbook authoring layer and adds only the missing
recalculation/readback step. I maintain Bilig, so verify it against your actual
workbook and keep Excel/LibreOffice/Graph in the loop when exact Excel behavior
or unsupported formulas matter.

Owned docs:

xlsx-populate

Useful when the question is: “How do I keep the formula and also get the result after generating a workbook?”

Answer shape:

xlsx-populate is the authoring layer. It can write the formula, but it does not
execute the workbook calculation engine and refresh the cached formula result.
That is why setting a formula and setting a value feel mutually exclusive.

Keep xlsx-populate for template/file generation, then run a recalculation step
before the service reads any formula outputs:

npx --package @bilig/xlsx-formula-recalc xlsx-recalc quote.xlsx \
  --set Inputs!B2=42 \
  --read Summary!B7 \
  --out quote.recalculated.xlsx \
  --json

I maintain Bilig; it is one local Node option. If the workbook uses macros,
pivots, external links, volatile formulas, or unsupported Excel functions, test
a reduced fixture against Excel/LibreOffice/Graph before treating the result as
production truth.

Owned docs:

Template-generated workbooks

Useful when the question is: “My template library emits formulas, but the output cell still has the old number.”

Answer shape:

Treat this as two steps:

1. Template the workbook.
2. Recalculate and read back the cells your code depends on.

The template step writes formulas. It usually does not own calculation. That is
fine for a downloadable report, but risky if a backend route or CI job trusts
the formula result before a spreadsheet app opens the file.

Start with a read-only detector:

npx --package @bilig/xlsx-formula-recalc xlsx-cache-doctor report.xlsx --json

Then recalculate only the inputs/outputs your service owns:

npx --package @bilig/xlsx-formula-recalc xlsx-recalc report.xlsx \
  --set Inputs!B2=48 \
  --read Summary!B7 \
  --out report.recalculated.xlsx \
  --json

I maintain Bilig, so verify formula coverage on your workbook and disclose the
boundary in production docs.

Owned docs:

CI or pull requests

Useful when the question is: “Can we catch stale formula caches before a bad workbook lands in main?”

Answer shape:

Use a report-only check first. The goal is not to rewrite workbooks in CI. The
goal is to tell reviewers: this formula cell has cached value X, recalculates
to Y, and this exact workbook path/cell needs attention.

Local no-clone proof:

npm exec --yes --package @bilig/xlsx-formula-recalc@latest -- bilig-evaluate --door xlsx-cache --json

Repo check:

npx --package @bilig/xlsx-formula-recalc xlsx-cache-doctor "fixtures/**/*.xlsx" --json

GitHub Action:

uses: proompteng/bilig@v1
with:
  workbooks: '**/*.xlsx'
  changed-files-only: 'true'
  fail-on-stale: 'false'

I maintain Bilig; start with report-only output so maintainers can see whether
the findings match their workbook workflow before making it blocking.

Owned docs:

When not to answer

Skip the public reply when:

Use owned docs instead. The strongest public answer is a small reproduction, a command the reader can run, and a clear boundary.