Generate native Excel .xlsx workbooks from JSON or TypeScript. Multi-sheet output with real cells, formulas, styles, merges, conditional formatting, tables, data validation, charts, comments, and images — emitted as genuine OOXML, not CSV.
npm install @paperjsx/json-to-xlsxRequires Node.js >=18. ESM + CJS.
import { SpreadsheetEngine } from "@paperjsx/json-to-xlsx";
import { writeFileSync } from "node:fs";
const buffer = await SpreadsheetEngine.render({
meta: { title: "Revenue Report", creator: "PaperJSX" },
sheets: [
{
name: "Revenue",
rows: [
{ cells: [{ value: "Quarter" }, { value: "Revenue" }] },
{ cells: [{ value: "Q1 2026" }, { value: 420000 }] },
{ cells: [{ value: "Q2 2026" }, { value: 465000 }] },
],
},
],
});
writeFileSync("revenue.xlsx", buffer);Output opens natively in Excel, Numbers, Google Sheets, and LibreOffice Calc — no compatibility layer.
- Native
.xlsx— real ECMA-376 OOXML with multiple sheets, real cells (not stringified), and full style fidelity. - Formulas — declarative
F.sum(),F.if(),F.vlookup(), and 40+ helpers that compile to proper A1 / R1C1 references. - Style dedup — fonts, fills, borders, and number formats are deduplicated via a style registry before serialization. No bloat.
- 17 style presets — ready-made named styles (
currency,percent,header,alert, etc.). - Conditional formatting — color scales, data bars, icon sets, expression rules.
- Tables — real Excel tables with filters and banded rows.
- Charts — 10+ chart types linked to sheet data.
- Comments, images, merges, data validation — first-class support.
- Streaming output —
renderStream()chunks large sheets to keep memory bounded. - Excel compliance — 1,048,576-row / 16,384-column limits enforced; the Lotus 1-2-3 phantom Feb 29, 1900 leap-year bug is handled; sheet name validation matches Excel exactly (no
[]:*?/\\, no leading/trailing apostrophes). - Deterministic output — same input, byte-identical workbook.
import type { SpreadsheetDocument } from "@paperjsx/json-to-xlsx";
const doc: SpreadsheetDocument = {
meta: { title, creator, subject, keywords },
sheets: [
{
name: "Summary",
columns: [{ width: 24 }, { width: 18, style: "currency" }],
rows: [
{
cells: [
{ value: "Q1 2026", style: "header" },
{ value: 420000 },
],
},
],
merges: ["A1:B1"],
freezePane: { row: 1, column: 0 },
},
],
};Build formulas declaratively with the F helpers — they produce the exact A1 string Excel expects, including reference shifting when you copy a formula across a range:
import { F } from "@paperjsx/json-to-xlsx";
{
cells: [
{ value: "Total" },
{ formula: F.sum("B2:B5") }, // =SUM(B2:B5)
{ formula: F.if(F.gt("C2", 1000), "High", "Low") }, // =IF(C2>1000,"High","Low")
{ formula: F.vlookup("A2", "Lookup!$A$2:$B$100", 2, false) },
],
}40+ builders cover math, lookup, logical, text, date/time, statistical, and financial functions. In the pro tier, evaluator.ts computes cached results server-side so cells display values in Excel immediately (without requiring F9 to recalculate).
{ value: 15678, style: "currency" } // $15,678.00 right-aligned
{ value: 0.342, style: "percent" } // 34.2%
{ value: "Region", style: "header" } // bold, background fill, borderAll 17 presets are named and composable; you can also define ad-hoc styles inline:
{
value: "Q1",
style: {
font: { bold: true, color: "#FFFFFF" },
fill: { type: "solid", color: "#0F172A" },
alignment: { horizontal: "center" },
border: { bottom: { style: "thin", color: "#94A3B8" } },
},
}{
name: "Sales",
rows: [ /* ... */ ],
conditionalFormats: [
{
range: "B2:B100",
type: "colorScale",
stops: [{ value: 0, color: "#FEE2E2" }, { value: 100000, color: "#BBF7D0" }],
},
{
range: "C2:C100",
type: "expression",
expression: "C2>100000",
style: { font: { bold: true, color: "#166534" } },
},
],
}import { SpreadsheetEngine } from "@paperjsx/json-to-xlsx";
import { createWriteStream } from "node:fs";
const out = createWriteStream("large.xlsx");
await SpreadsheetEngine.renderStream(doc, {
rowChunkSize: 2000, // 100–10,000, default 1,000
onChunk: (chunk) => out.write(chunk),
onEnd: () => out.end(),
});SpreadsheetEngine.render(doc, options?) // Uint8Array
SpreadsheetEngine.renderStream(doc, handlers) // chunked output
SpreadsheetEngine.validateDocument(doc) // throws ZodError if invalid
SpreadsheetEngine.renderValidated(validated, opts?) // skip re-validation
// Formula builder
F.sum, F.if, F.and, F.or, F.not, F.vlookup, F.hlookup, F.xlookup,
F.index, F.match, F.countif, F.sumif, F.average, F.min, F.max,
F.round, F.concat, F.text, F.date, F.today, F.now, /* 40+ total */
// Utilities
cellRef.parse("B7") // { column: 2, row: 7 }
cellRef.format(2, 7) // "B7"
excelSerialDate(date) // Excel date serial number
// Errors
SpreadsheetErrorFull type surface in dist/index.d.ts.
import { setDeterministicMode } from "@paperjsx/json-to-xlsx";
setDeterministicMode(true);Freezes timestamps, relationship IDs, and style indices so the same input produces byte-identical output.
import { SpreadsheetError } from "@paperjsx/json-to-xlsx";
try {
await SpreadsheetEngine.render(doc);
} catch (err) {
if (err instanceof SpreadsheetError) {
console.error(err.code, err.message, err.path);
}
throw err;
}Validation errors include the offending cell reference (e.g. Sheet1!C7, not rows[5].cells[2]) so debugging large sheets is practical.
- Rows capped at 1,048,576; columns at 16,384.
- Sheet names limited to 31 chars, cannot start or end with
', cannot contain[]:*?/\\. - Dates before Dec 31, 1899 produce negative serials and have undefined Excel behavior — validate upstream if your data may include them.
- CJK column width uses a 1.8× multiplier heuristic. Override with explicit
columns[i].widthfor pixel-exact layout.
@paperjsx/json-to-xlsx-pro adds:
- commercial / self-hosted production license
- server-side formula evaluation (cached results so Excel renders without F9)
- workbook repair (corrupted
.xlsx→ valid.xlsx) - quality reporting (
preflight()with memory estimation + issue surface) - template parsing and injection (ingest existing
.xlsxfiles as templates) - advanced chart features, pivot tables
The API is identical — swap the import and provide PAPERJSX_LICENSE_KEY.
- Docs: paperjsx.com/docs
- Playground: paperjsx.com/playground
- Pricing: paperjsx.com/pricing
Apache-2.0. See LICENSE.