Patching
Patch an existing .xlsx template in three ways: replace {{placeholder}} tokens in cells, find-and-replace literal text, or override document metadata.
patchWorkbook
Replaces placeholders in an existing .xlsx file:
import { patchWorkbook } from "@office-open/xlsx";
import { readFileSync, writeFileSync } from "node:fs";
const result = await patchWorkbook({
outputType: "nodebuffer",
data: readFileSync("template.xlsx"),
placeholders: {
name: "John Doe",
amount: 1500,
date: new Date("2024-12-31"),
},
});
writeFileSync("output.xlsx", result);
How It Works
The patcher scans every worksheet for cells whose text matches the placeholder pattern (default {{key}}), looking in the shared-strings table, inline strings, and print headers/footers. Placeholders that span multiple runs (split by formatting) are handled automatically.
Placeholder values
Each placeholder is a plain scalar — string, number, boolean, or Date:
placeholders: {
name: "Alice", // String
quantity: 42, // Number
active: true, // Boolean
deadline: new Date("2024-12-31"), // Date
}
When a placeholder is the entire cell content, the patch rewrites the cell to the matching typed value:
| Value type | Resulting cell |
|---|---|
string | Text substitution (cell stays a string) |
number | Numeric cell (<v> with no t, default numeric) |
boolean | Boolean cell (t="b", <v>1/0) |
Date | Numeric cell holding the Excel serial date |
When the placeholder is embedded in larger text (e.g. Total: {{amount}}), the value is substituted as text, keeping the cell a string.
Find and Replace
Replace literal text without delimiters — keys are matched verbatim. Works in cell values and print headers/footers:
const result = await patchWorkbook({
outputType: "nodebuffer",
data: templateBuffer,
findReplace: {
"Acme Corp": "Globex Inc.",
Draft: "Final",
},
});
Core Properties
Override document metadata (docProps/core.xml), merged over existing values:
const result = await patchWorkbook({
outputType: "nodebuffer",
data: templateBuffer,
coreProperties: { title: "Q4 Report", creator: "Jane Doe" },
});
Worksheets
Append new worksheets or replace existing ones by sheet name. Each entry reuses the full WorksheetOptions vocabulary from generateWorkbook:
const result = await patchWorkbook({
outputType: "nodebuffer",
data: templateBuffer,
worksheets: {
append: [
{
name: "Summary",
rows: [{ cells: [{ reference: "A1", value: "Appended sheet" }] }],
},
],
replace: {
Sheet1: { rows: [{ cells: [{ reference: "A1", value: "Replaced" }] }] },
},
},
});
The shared-strings table is rebuilt from the template first, so appended and replaced worksheets continue indexing strings at the correct offset — existing cell references stay valid. Appended worksheets are wired into workbook.xml, the workbook relationships, and [Content_Types].xml. Cell styles on appended rows are not supported — reference only styles already present in the template.
Comments
Append cell comments (notes) to existing worksheets, keyed by sheet name. Each comment reuses the CommentOptions vocabulary from generateWorkbook (see ) — cell, author, and text:
const result = await patchWorkbook({
outputType: "nodebuffer",
data: templateBuffer,
comments: {
Report: [
{ cell: "B2", author: "Alice", text: "Above target" },
{ cell: "B3", author: "Bob", text: "Needs follow-up" },
],
},
});
Existing comments on a worksheet are preserved — new ones are appended, authors are re-collected, and the worksheet relationship, VML drawing, and content-type wiring are added when the parts are new.
Custom Delimiters
Default delimiters are {{ and }}. Change them with placeholderDelimiters:
await patchWorkbook({
outputType: "nodebuffer",
data: templateBuffer,
placeholders: { name: "John" },
placeholderDelimiters: { start: "<<", end: ">>" },
});
Output Types
outputType | Returns |
|---|---|
"nodebuffer" | Buffer |
"uint8array" | Uint8Array |
"arraybuffer" | ArrayBuffer |
"base64" | string |
"blob" | Blob |
"string" | string |
Options
| Option | Type | Default | Description |
|---|---|---|---|
outputType | string | — | Output format (see table above) |
data | Buffer | Uint8Array | ... | — | Input .xlsx file data |
placeholders | Record<string, ScalarValue> | — | Delimiter-wrapped placeholder → value (string | number | boolean | Date) |
findReplace | Record<string, ScalarValue> | — | Literal find string → value (no delimiters) |
coreProperties | Partial<CorePropertiesOptions> | — | Core metadata override, merged over existing values |
worksheets | { append?, replace? } | — | Append worksheets or replace worksheets by sheet name |
comments | Record<string, CommentOptions[]> | — | Append cell comments by sheet name (merged with existing) |
placeholderDelimiters | { start: string, end: string} | { start: "{{", end: "}}" } | Custom placeholder delimiters |
Tips
- Placeholders are replaced in all worksheets, shared strings, and print headers/footers.
- The original cell's style is preserved when replacing the value.
- A
number,boolean, orDatewhose placeholder fills the whole cell becomes a real typed cell. placeholdersandfindReplaceshare one engine; combine both in a single call.