Node / SSR Usage
In Node servers (including SSR) you don't need browser assets and there is no initialization boilerplate: the engine locates the shipped modern-xlsx.wasm on disk (in this package's own dist/, pnpm-symlink-safe) and initializes it synchronously on first use. The explicit initWasmSync bootstrap from earlier versions is no longer required — keep it only if you want the one-off read+compile at startup instead of the first request.
Auto-initialization does a one-off synchronous file read plus WASM compile (measured ~20ms on this repo's dev machine, Node 22: ~4ms to read the 1.9MB binary, ~15ms to compile), charged to the first export. To move that cost to process startup instead, use the explicit init below.
Environment differences
| Dimension | Browser | Node / SSR |
|---|---|---|
| Worker path | available | no Web Worker; falls back to main/stream |
| Auto download | triggers download | triggerDownload is a no-op |
download option | defaults to true | already a no-op in Node; set false for explicitness and handle the Blob |
| Large data | worker + Fast stream | main → stream at ≥ 50k rows (main thread) |
| WASM init | auto-located (default) | auto-located and initialized |
Export and write to disk
import { exportExcel } from "@marcusok/excel-exporter";
import { writeFile } from "node:fs/promises";
const result = await exportExcel({
filename: "server-report",
download: false, // never trigger a browser download server-side
sheets: [{ name: "Sheet1", columns: [...], data: [...] }],
});
if (result.success && result.blob) {
const buffer = Buffer.from(await result.blob.arrayBuffer());
await writeFile("./server-report.xlsx", buffer);
}With a framework (Next.js Route Handler)
// app/api/export/route.ts
import { exportExcel } from "@marcusok/excel-exporter";
export async function GET() {
const result = await exportExcel({
filename: "report",
download: false,
sheets: [/* ... */],
});
if (!result.success || !result.blob) {
return Response.json({ error: result.error?.message }, { status: 500 });
}
return new Response(result.blob, {
headers: {
"Content-Type":
"application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
"Content-Disposition": 'attachment; filename="report.xlsx"',
},
});
}Optional: explicit init timing
To move the one-off synchronous WASM read+compile from the first request to process startup, await the loader before serving traffic:
import { getWasmLoader } from "@marcusok/excel-exporter";
await getWasmLoader().ensureLoaded(); // reads + compiles the shipped wasm onceDo not use
initWasmSyncfrom a separately installedmodern-xlsxfor this: the engine is bundled into this package's owndist, so an external copy initializes a different module instance and does not pre-warm the bundled one.
Bundler caveat: if your server build bundles this package and the WASM asset is not emitted alongside the bundle, the automatic disk lookup fails and WASM-dependent routes degrade to the style-less stream (headers/merges preserved). Either keep the package external (the default for Node server builds), pass
configureWasm({ wasmUrl })with an HTTP URL, or copy the asset where the bundle can read it.
Performance tip
Large server-side exports (≥ 50k rows) automatically take the stream path; without a Worker, Fast stream occupies the current thread for ~0.8s. Run it in an async task or queue so request threads stay responsive.