Library API
The programmatic API for generating documents from Node.js (or any JS runtime for the parts that don't touch the filesystem). Install @json-to-office/json-to-docx for Word documents and @json-to-office/json-to-pptx for PowerPoint presentations — each package is a thin facade that re-exports the generation functions, validators, schemas, and types you need.
pnpm add @json-to-office/json-to-docx @json-to-office/json-to-pptxBoth packages require Node >= 20, and both declare their rendering backend as a peer dependency: docx@9.7.1 for @json-to-office/json-to-docx, pptxgenjs@^3.12.0 for @json-to-office/json-to-pptx.
Where functions live
Everything documented here is importable from the two public packages, with a few exceptions that live in @json-to-office/core-docx (a published dependency of json-to-docx): generateBufferFromFile, generateAndSaveFromFile, the theme JSON helpers, and the DOCX plugin API. Each is flagged below.
DOCX generation
import {
generateAndSaveFromJson,
generateBufferFromJson,
} from '@json-to-office/json-to-docx';
await generateAndSaveFromJson(
{
name: 'docx',
props: { theme: 'minimal' },
children: [
{ name: 'heading', props: { text: 'Q1 Report', level: 1 } },
{
name: 'paragraph',
props: { text: 'Revenue grew **32%** quarter-over-quarter.' },
},
],
},
'report.docx'
);Renderer-native APIs were removed in 0.39
Generation compiles to an internal representation and hands it to a renderer adapter, so no public API returns or accepts a docx object any more. Everything that did is gone:
| Removed | Use instead |
|---|---|
generateDocument, generateDocumentFromJson, generateDocumentFromFile | generateBufferFromJson / generateBufferWithWarnings / generateBufferFromFile |
saveDocument(document, …), generateFromConfig | generateAndSaveFromJson / generateAndSaveFromFile |
DocumentGenerator.generate(document, options?) | generateBuffer(document, options?) or generateFile(document, path, options?) |
DocumentGeneratorOptions.enableCache | — (the component render cache went with the writer layer; the option was a no-op) |
parseTextWithDecorators, renderComponent, createTypedImageRun | — (they were the writer layer) |
generateBuffer returns { buffer, warnings, standardDefinition, preservedDefinition? } where generate returned { document, … }; every other field is unchanged, so the migration is usually one method name and reading buffer instead of packing document yourself.
Functions
Except where noted below, these functions accept an optional JsonGenerationOptions as their last parameter. Every entry point returns bytes or writes a file: no renderer object crosses the package boundary, so the backend that produced them stays swappable through the renderer option.
| Function | Signature | Description |
|---|---|---|
generateBufferFromJson | (jsonConfig: string | object, options?) => Promise<Buffer> | Main entry point. Accepts a JSON string or an already-parsed object, and packs a .docx buffer — the usual choice for HTTP responses. Validates against the document schema first unless options.validation.enabled === false; throws JsonValidationError on schema errors and JsonParsingError (code JSON_PARSE_ERROR) on malformed JSON strings. |
generateBufferWithWarnings | (jsonConfig, options?) => Promise<DocxGenerationResult> | Same, returning { buffer, warnings } so a caller can surface what was substituted or dropped instead of leaving it on the console. |
generateBufferFromConfig | (props, components, options?) => Promise<Buffer> | Build from the document's props and children directly, without wrapping them in a root docx node. |
generateAndSaveFromJson | (jsonConfig, filename, options?) => Promise<void> | Generate and write to disk in one call. |
generateBufferFromFile | (filePath, options?) => Promise<Buffer> | Load a .docx.json file; buffer out. |
generateAndSaveFromFile | (inputFilePath, outputFilePath, options?) => Promise<void> | File in, .docx file out. |
validateJsonSchema | (jsonConfig: string | object) => DocumentValidationResult | Validate without generating. Returns { valid, errors, documentType: 'docx', ... } — see Validation. |
import {
generateBufferFromJson,
validateJsonSchema,
} from '@json-to-office/json-to-docx';
const result = validateJsonSchema(jsonFromClient);
if (!result.valid) {
console.error(result.errors); // [{ path, message, code?, suggestions? }, ...]
} else {
const buffer = await generateBufferFromJson(jsonFromClient);
// send buffer as application/vnd.openxmlformats-officedocument.wordprocessingml.document
}JsonGenerationOptions
| Option | Type | Default | Description |
|---|---|---|---|
validation.enabled | boolean | true | Validate the definition before building; schema errors throw JsonValidationError. |
validation.allowUnknownFields | boolean | false | Ignore unknown props during validation — a migration escape hatch. Do not rely on it to return or render a recursively stripped clone. |
customThemes | Record<string, ThemeConfig> | — | Custom themes keyed by name; props.theme in the document is matched case-insensitively against this map before falling back to built-in themes. See Themes & styling. |
services | ServicesConfig | — | External service wiring for highcharts and visual components. |
fonts | FontRuntimeOpts | — | Font resolution: extra registry entries, Google Fonts fetching, export mode, strictness. See Fonts. |
renderer | 'docxjs' | 'office-open' | 'docxjs' | Backend that turns the compiled document into bytes. docxjs is the default and produces the output this pipeline has always produced. office-open is experimental, opt-in, and fails before rendering on any feature it cannot express. |
baseDir | string | process.cwd() | Directory that relative asset paths (image path props) resolve against. |
warnings | GenerationWarning[] | — | Pass an array to collect non-fatal warnings; without it, warnings go to console.warn. |
outputPath | string | — | Optional output path hint. |
deterministic | boolean | true | Normalize volatile OOXML metadata and ZIP timestamps so equivalent input yields byte-identical output. Set false to stamp the real wall clock instead. See Reproducible output. |
generatedAt | string | Date | epoch | Timestamp written into package metadata and {DATE} / {DATETIME} placeholders. Defaults to a stable 2000-01-01T00:00:00Z. Must be a valid date on or after 1980-01-01 (a ZIP format limit) or generation throws. |
flattenVisuals
Replaces every enabled visual component with a plain image (base64 PNG), producing a portable .docx.json that renders anywhere with no rasterization service. It walks children, section headers/footers, and table cell content.
import {
flattenVisuals,
type FlattenVisualsOptions,
} from '@json-to-office/json-to-docx';
const portable = await flattenVisuals(doc, {
rasterize, // required: a PptxRasterizer (see ServicesConfig below)
dpi: 200, // default 200
concurrency: 4, // default 4
});Visuals with enabled: false are left untouched; id and enabled are preserved on the resulting image nodes.
diffDocuments
Word-level document diffing that produces a redline document with native Word tracked changes (re-exported from @json-to-office/shared-docx through the main package).
import { diffDocuments } from '@json-to-office/json-to-docx';
const { document, summary } = diffDocuments(oldDoc, newDoc, {
author: 'Legal review', // default "json-to-office"
date: '2026-08-15T00:00:00Z', // default: deterministic epoch
});
// document → renderable redline; root gains trackRevisions: true
// summary → { tracked: { modified, inserted, deleted }, untracked, unchangedBlocks, notes }Both inputs must be docx definitions. Paragraphs, headings, and list items diff as tracked insertions/deletions; structural changes the redline cannot express (tables, images, charts) are replaced and reported in summary.untracked. The result renders with any of the generate functions above.
Theme JSON helpers
Load, validate, and export DOCX theme files. Import from @json-to-office/core-docx:
| Function | Signature | Description |
|---|---|---|
loadThemeFromJson | (jsonString) => Promise<ThemeConfigJson> | Parse and validate a theme from a JSON string. |
loadThemeFromFile | (filePath) => Promise<ThemeConfigJson> | Load from disk. Hardened: .json extension only, 10 MB max, no path traversal. |
exportThemeToJson | (theme, pretty = true) => string | Serialize a theme back to JSON. |
validateThemeJsonString | (jsonString) => ValidationResult | Validate without parsing into a usable theme. |
createMinimalTheme | () => ThemeConfigJson | A minimal valid theme to start from. |
Failures throw typed errors: ThemeValidationError, ThemeParseError, ThemeFileError.
import { loadThemeFromFile } from '@json-to-office/core-docx';
import { generateAndSaveFromJson } from '@json-to-office/json-to-docx';
const brand = await loadThemeFromFile('./brand.docx.theme.json');
await generateAndSaveFromJson(doc, 'report.docx', {
customThemes: { [brand.name]: brand },
});PPTX generation
import { generateBufferWithWarnings } from '@json-to-office/json-to-pptx';
const { buffer, warnings } = await generateBufferWithWarnings({
name: 'pptx',
props: {
title: 'Demo',
theme: 'default',
slideWidth: 13.33,
slideHeight: 7.5,
},
children: [
{
name: 'slide',
props: { background: { color: 'background' } },
children: [
{
name: 'text',
props: {
text: 'Hello',
style: 'title',
grid: { column: 0, row: 0, columnSpan: 12, rowSpan: 2 },
},
},
],
},
],
});
for (const w of warnings) console.warn(`[${w.code}] ${w.message}`);Functions
| Function | Signature | Description |
|---|---|---|
generateBufferFromJson | (jsonConfig: string | object, options?) => Promise<Buffer> | JSON in, .pptx buffer out. |
generateBufferWithWarnings | (jsonConfig, options?) => Promise<GenerationResult> | The recommended entry point: returns { buffer, warnings } so you can surface pipeline warnings. Also normalizes inline theme objects and runs the font export-mode pre-pass. |
generateAndSaveFromJson | (jsonConfig, outputPath, options?) => Promise<void> | Generate and write to disk. |
generateFromFile | (filePath, outputPath) => Promise<void> | .pptx.json file in, .pptx file out. |
Renderer-native APIs were removed in 0.37
generatePresentation (which returned a PptxGenJS instance) and savePresentation are gone. Generation now compiles to an internal representation and hands it to a renderer adapter, so no public API returns or accepts a backend object. Use generateBufferFromJson / generateBufferWithWarnings and write the buffer yourself, or generateAndSaveFromJson.
GenerationResult is { buffer: Buffer; warnings: PipelineWarning[] }, where each warning is { code, message, component?, slide? }. The exported WarningCodes registry lists the standard codes (UNKNOWN_COMPONENT, CHART_INVALID_SERIES, IMAGE_NO_SOURCE, GRID_POSITION_CLAMPED, FONT_UNRESOLVED, …). HYPERLINK_SLIDE_UNRESOLVED is also emitted but lives outside that registry. See PPTX warnings.
PPTX generation validates, like DOCX
Generation runs the schema validator before rendering and throws PresentationValidationError on schema errors — set options.validation.enabled = false to skip it. Pipeline warnings cover only recoverable problems found later. See Validation and PPTX warnings.
GenerationOptions
| Option | Type | Default | Description |
|---|---|---|---|
customThemes | Record<string, PptxThemeConfig> | — | Custom themes keyed by name, referenced by props.theme in the document. A PPTX document can also inline a full theme object directly in props.theme — no options needed. |
services | ServicesConfig | — | e.g. { highcharts: { serverUrl, headers } } for the highcharts component. |
fonts | FontRuntimeOpts | — | Font resolution and export-mode handling, same shape as DOCX. |
renderer | 'pptxgenjs' | 'office-open' | 'pptxgenjs' | Backend that turns the compiled presentation into bytes. pptxgenjs is the default and produces the output this pipeline has always produced. office-open is experimental, opt-in, and fails before rendering on any feature it cannot express. |
validation | GenerationValidationOptions | — | { enabled, allowUnknownFields }. Validation runs before rendering and throws PresentationValidationError; set enabled: false to skip it. |
deterministic | boolean | true | Normalize package metadata and ZIP timestamps for byte-identical output, including the XLSX packages embedded in native charts. See Reproducible output. |
generatedAt | string | Date | epoch | Timestamp written into package metadata. Defaults to a stable 2000-01-01T00:00:00Z; must be on or after 1980-01-01 or generation throws. |
Quality analysis
Design-quality analysis is an explicit core API. It is not re-exported by the json-to-* facade packages, and direct library generation does not apply a quality gate automatically:
import { analyzeDocxQuality } from '@json-to-office/core-docx';
import { analyzePptxQuality } from '@json-to-office/core-pptx';
const analysis = analyzePptxQuality(deck, {
profile: { id: 'executive-presentation', formats: ['pptx'] },
policy: { gate: 'warning' },
});
if (analysis.blocked) throw new Error('Quality gate failed');Both analyzers are synchronous and accept { customThemes?, renderer?, profile?, policy?, prepared? }. They return a QualityAnalysis containing diagnostics, severity counts, the gate verdict, suppression/truncation metadata and rule errors. The cores also export their format facts, profiles, rule packs and prepared-document helpers; @json-to-office/quality exports the shared engine and contracts. See Design quality for rules, profiles, policy precedence and limits.
Plugin API
Custom components are semver-versioned units with a TypeBox props schema and an async render() that expands into standard components (or other custom components — nesting is re-expanded recursively up to 20 levels). See Architecture for how the processor pipeline works.
createComponent and createVersion
Shared between both formats (each package re-exports them — from @json-to-office/json-to-pptx for PPTX, from @json-to-office/core-docx for DOCX):
import { Type } from '@sinclair/typebox';
import { createComponent, createVersion } from '@json-to-office/core-docx';
const kpiCard = createComponent({
name: 'kpi-card',
versions: {
'1.0.0': createVersion({
propsSchema: Type.Object({
label: Type.String(),
value: Type.String(),
}),
async render({ props, theme, addWarning }) {
return [
{
name: 'statistic',
props: { number: props.value, description: props.label },
},
];
},
}),
},
});versionsmaps semver strings to version entries; a document can pin a version, and an omitted version resolves to the latest.- Each version is
{ propsSchema, render, hasChildren?, description? }. render(context)receives{ props, theme, addWarning, children? }— validated props, the resolved theme, a warning collector, and processed children for container components — and returns aPromiseof an array of components.
createDocumentGenerator (DOCX)
Import from @json-to-office/core-docx. Returns a chainable, type-accumulating builder:
import { createDocumentGenerator } from '@json-to-office/core-docx';
const generator = createDocumentGenerator({ theme: myTheme }).addComponent(
kpiCard
);
const { buffer, warnings } = await generator.generateBuffer({
name: 'docx',
props: {},
children: [{ name: 'kpi-card', props: { label: 'ARR', value: '$1.2M' } }],
});Options (DocumentGeneratorOptions):
| Option | Type | Default | Description |
|---|---|---|---|
theme | ThemeConfig | — | Default theme when no custom or built-in theme matches. |
customThemes | Record<string, ThemeConfig> | — | Custom themes resolved per-document via props.theme. |
debug | boolean | false | Debug logging. |
services | ServicesConfig | — | Highcharts / pptx-rasterizer wiring. |
fonts | FontRuntimeOpts | — | Font resolution options. |
validation | GenerationValidationOptions | on | Default validation behavior for every generate call; per-call options override. |
deterministic | boolean | true | Normalize volatile OOXML values so the same document produces the same bytes. |
generatedAt | string | Date | epoch | Timestamp written into document metadata. |
baseDir | string | cwd() | Directory relative image path props resolve against; per-call options.baseDir overrides it. |
renderer | 'docxjs' | 'office-open' | 'docxjs' | Backend that turns the compiled document into bytes. office-open is experimental, opt-in, and fails before rendering on any feature it cannot express. |
Builder methods:
| Method | Returns | Description |
|---|---|---|
addComponent(component) | new builder | Registers a custom component; TypeScript accumulates the component types so documents are fully typed. |
generateBuffer(document, options?) | Promise<{ buffer, warnings, standardDefinition, ... }> | Expand plugins and pack a .docx buffer. standardDefinition is the fully-expanded standard-component tree. |
generateFile(document, outputPath, options?) | Promise<{ warnings, standardDefinition, ... }> | Same, written to disk. |
expandStandardDefinition(document, options?) | Promise<{ standardDefinition, warnings }> | Expansion only — no fonts, no layout, no rendering, no external services. Use it when you want the JSON tree and not a document. |
validate(document) | { valid, errors? } | Validate against the enriched (standard + custom) schema. |
getComponentNames() | string[] | Registered custom component names. |
generateSchema(includeStandardComponents = true) | TSchema | The enriched TypeBox schema. |
exportSchema(outputPath, { includeStandardComponents?, prettyPrint? }) | Promise<void> | Write the enriched schema as JSON Schema — see JSON Schemas. |
getStandardComponentsDefinition(document) | Promise<ReportComponentDefinition> | Deprecated. Runs a second expansion pass; read standardDefinition off a generate result, or call expandStandardDefinition. |
There is no generate(): it returned a docx.js Document, and no public API hands out a backend object any more. The table at the top of this section maps it and its neighbours onto what replaced them.
createPresentationGenerator (PPTX)
Import from @json-to-office/json-to-pptx. Same shape, PPTX flavored:
import { createPresentationGenerator } from '@json-to-office/json-to-pptx';
const generator = createPresentationGenerator({ theme: 'dark' }).addComponent(
myCalloutComponent
);
const { buffer, warnings } = await generator.generate(deckJson);
await generator.generateFile(deckJson, './deck.pptx'); // → { warnings }Options (PresentationGeneratorOptions): theme? (PptxThemeConfig | string), customThemes?, debug?, services?, fonts?.
Builder methods: addComponent(component), generate(document) → Promise<{ buffer, warnings }>, generateFile(document, outputPath) → Promise<{ warnings }>, getComponentNames(), validate(document) → { valid, errors? }, generateSchema() → TSchema, exportSchema(outputPath, { prettyPrint? }).
Shared option shapes
ServicesConfig
Wires the two components that need an external renderer: highcharts (both formats) and the DOCX visual component. See Render server for hosting options.
interface ServicesConfig {
highcharts?: {
serverUrl?: string; // Highcharts Export Server (default http://localhost:7801)
headers?:
| Record<string, string>
| ((
body: unknown
) => Record<string, string> | Promise<Record<string, string>>);
};
pptx?: {
// In-process rasterizer — takes precedence over serverUrl.
render?: (request: { presentation: unknown; dpi: number }) => Promise<{
base64DataUri: string; // data:image/png;base64,...
width: number;
height: number;
}>;
serverUrl?: string; // HTTP rasterizer (default http://localhost:7802), POST /rasterize
headers?:
| Record<string, string>
| ((
body: unknown
) => Record<string, string> | Promise<Record<string, string>>);
dpi?: number; // default DPI when a visual doesn't specify one (default 200, clamped 36-600)
};
}services.pptx is needed only by visual components that rasterize. A visual with "renderMode": "native" is drawn by the office-open backend itself — it never reaches this service, stages no fonts for it and moves none of its counters — so a document whose visuals are all native generates with services omitted entirely. See Native mode.
FontRuntimeOpts
Runtime font behavior — not serializable (it can carry Buffers and a callback), so it never lives in the document JSON. Full guide: Fonts.
| Option | Type | Default | Description |
|---|---|---|---|
extraEntries | FontRegistryEntry[] | — | Extra font registry entries (Google Fonts, local files, URLs, base64 data) merged over the document's registry. |
googleFonts | { enabled?, cacheDir?, fetchTimeoutMs? } | fetching enabled | Google Fonts auto-fetch configuration. |
strict | boolean | false | Promote FONT_UNRESOLVED warnings to thrown errors. |
mode | 'custom' | 'substitute' | 'custom' | custom keeps font references as-authored; substitute rewrites every non-safe family to a SAFE_FONTS equivalent so the file renders identically everywhere. |
substitution | Record<string, string> | category-based defaults | Family → safe-font map applied in substitute mode. |
baseDir | string | cwd | Base directory for kind: "file" font sources. |
onResolved | (fonts: ResolvedFont[]) => void | — | Called once per generate with materialized font bytes — used by the playground to stage fonts for LibreOffice PDF preview. Office output itself never embeds font bytes. |
Related
- Getting started — end-to-end setup
- CLI reference — the same pipeline from the command line
- Validation — validators, error shapes, strict vs lenient
- JSON Schemas — generated schemas for editors and LLMs
- DOCX components and PPTX components — every prop of every component