XLSX

Patching

Modify existing .xlsx files by replacing placeholders, literal text, or metadata

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 typeResulting cell
stringText substitution (cell stays a string)
numberNumeric cell (<v> with no t, default numeric)
booleanBoolean cell (t="b", <v>1/0)
DateNumeric 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

outputTypeReturns
"nodebuffer"Buffer
"uint8array"Uint8Array
"arraybuffer"ArrayBuffer
"base64"string
"blob"Blob
"string"string

Options

OptionTypeDefaultDescription
outputTypestringOutput format (see table above)
dataBuffer | Uint8Array | ...Input .xlsx file data
placeholdersRecord<string, ScalarValue>Delimiter-wrapped placeholder → value (string | number | boolean | Date)
findReplaceRecord<string, ScalarValue>Literal find string → value (no delimiters)
corePropertiesPartial<CorePropertiesOptions>Core metadata override, merged over existing values
worksheets{ append?, replace? }Append worksheets or replace worksheets by sheet name
commentsRecord<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, or Date whose placeholder fills the whole cell becomes a real typed cell.
  • placeholders and findReplace share one engine; combine both in a single call.
Copyright © 2026