Package Information
Documentation
n8n-nodes-universal-templater
An n8n community node that generates DOCX, XLSX, Markdown, and TXT files
from templates using a single, standardised JSON data structure.
Supported Formats
| Format | Engine | Template Syntax |
|---|---|---|
| DOCX | docxtemplater | {key}, {#each rows}…{/each} |
| XLSX | ExcelJS | {{key}}, {{rows[*].col}} |
| Markdown | Handlebars | {{key}}, {{#each rows}}…{{/each}} |
| TXT | Handlebars | same as Markdown |
Installation
In an existing n8n instance
# Inside the n8n user data directory
npm install n8n-nodes-universal-templater
Restart n8n. The Universal Templater node will appear in the node palette under
the Transform group.
Local / development install
git clone https://github.com/your-org/n8n-nodes-universal-templater.git
cd n8n-nodes-universal-templater
npm install
npm run build
# Link into your local n8n
cd ~/.n8n/nodes # or wherever N8N_CUSTOM_EXTENSIONS points
npm link /path/to/n8n-nodes-universal-templater
Node Parameters
| Parameter | Type | Default | Description |
|---|---|---|---|
| Output Format | Select | DOCX | The format of the file to generate. |
| Input Binary Property | String | data |
Binary property on the input item that holds the template file. |
| Template Data | JSON | {} |
Data object injected into the template. |
| Output File Name | String | output |
Base name for the output file (extension is added automatically). |
| Output Binary Property | String | data |
Binary property on the output item where the rendered file will be written. |
JSON Data Structure
The node expects a flat-or-nested JSON object. The recommended standardised shape is:
{
"title": "My Report",
"author": "John Doe",
"date": "2024-01-01",
"rows": [
{ "name": "Item 1", "price": 10.00, "qty": 2 },
{ "name": "Item 2", "price": 25.50, "qty": 1 }
]
}
All engines accept this shape. Scalar fields (title, author, date) are substituted
wherever their placeholder appears. The rows array (or any other array) drives row
expansion in XLSX and loop iteration in DOCX / Handlebars templates.
Template Syntax by Format
DOCX (docxtemplater)
docxtemplater uses single-brace tags inside a valid .docx file.
Dear {firstName} {lastName},
Please find below your order summary dated {date}:
{#items}
- {name}: {qty} × ${price}
{/items}
Total items: {totalItems}
Tips:
- Tags must be styled normally inside Word — do not split them across formatting runs.
- Use
{#arrayName}…{/arrayName}for loops. - Use
{?condition}…{/condition}for conditionals. - See the docxtemplater docs for the full syntax.
XLSX (ExcelJS)
Place placeholder strings directly in cell values within a .xlsx template file.
Scalar replacement — any cell whose text contains {{key}} will have the token
replaced with the matching value from the data object:
Cell A1: {{title}}
Cell B1: Generated on {{date}}
Array / table expansion — place one template row whose cells use the pattern{{arrayName[*].propertyName}}:
| Column A | Column B | Column C |
|---|---|---|
{{rows[*].name}} |
{{rows[*].price}} |
{{rows[*].qty}} |
At render time the node will:
- Detect that row as a template row for the
rowsarray. - Duplicate the row once per item in
data.rows. - Fill each cell with the corresponding item property value.
- Delete the original template row.
Multiple independent template rows (for different arrays) are supported within the
same sheet. They are processed bottom-up to keep row numbers stable.
Markdown & TXT (Handlebars)
Both formats use the full Handlebars templating language.
The template is stored as binary text (UTF-8) on the input item.
Basic interpolation:
# {{title}}
**Author:** {{author}}
**Date:** {{date}}
Loops:
## Line Items
{{#each rows}}
- **{{name}}** — qty: {{qty}}, price: ${{fixed price 2}}
{{/each}}
Conditionals:
{{#if rows}}
The report contains {{rows.length}} items.
{{else}}
No items found.
{{/if}}
Built-in helpers registered by this node:
| Helper | Description |
|---|---|
{{eq a b}} |
True if a === b |
{{gt a b}} |
True if a > b |
{{lt a b}} |
True if a < b |
{{gte a b}} |
True if a >= b |
{{lte a b}} |
True if a <= b |
{{ne a b}} |
True if a !== b |
{{json obj}} |
Pretty-print an object as JSON |
{{upper str}} |
Convert to UPPER CASE |
{{lower str}} |
Convert to lower case |
{{trim str}} |
Remove leading/trailing whitespace |
{{default val fallback}} |
Return val if truthy, else fallback |
{{add a b}} |
a + b |
{{subtract a b}} |
a - b |
{{multiply a b}} |
a × b |
{{divide a b}} |
a / b (returns 0 on divide-by-zero) |
{{fixed num digits}} |
Format number to fixed decimal places |
{{formatDate dateStr locale}} |
Format a date string using toLocaleDateString |
Examples
Example 1 — Generate a Word invoice
Workflow:
- Read Binary File node — reads
invoice_template.docxinto binary propertydata. - Set node — sets
jsonDatato the invoice data JSON. - Universal Templater — format: DOCX, data property:
data, output:invoice_2024.docx. - Write Binary File or Send Email — uses the
databinary output.
Template data:
{
"invoiceNumber": "INV-2024-001",
"clientName": "Acme Corp",
"date": "2024-01-15",
"rows": [
{ "description": "Consulting services", "hours": 8, "rate": 150.00 },
{ "description": "Expense reimbursement", "hours": 0, "rate": 75.00 }
],
"total": 1275.00
}
Excerpt from invoice_template.docx:
Invoice #: {invoiceNumber}
Client: {clientName}
Date: {date}
{#rows}
{description} | {hours}h | ${rate}
{/rows}
Total: ${total}
Example 2 — Generate a Markdown report via HTTP
Workflow:
- HTTP Request node — GET
https://api.example.com/data→ JSON response. - Function node — transforms API response into the standard data shape.
- Read Binary File node — reads
report_template.md→ binarytemplate. - Universal Templater — format: Markdown, input binary property:
template,
template data from expression{{ $json }}, output file name:report. - Write Binary File — saves
report.md.
Example 3 — Excel report with table expansion
Template sales_template.xlsx cell layout:
A1: {{title}} |
B1: (blank) | C1: (blank) |
|---|---|---|
A2: Month |
B2: Revenue |
C2: Units |
A3: {{rows[*].month}} |
B3: {{rows[*].revenue}} |
C3: {{rows[*].units}} |
Template data:
{
"title": "Sales Report Q1 2024",
"rows": [
{ "month": "January", "revenue": 45200, "units": 312 },
{ "month": "February", "revenue": 51800, "units": 389 },
{ "month": "March", "revenue": 63100, "units": 441 }
]
}
Output: Row 1 gets Sales Report Q1 2024 in A1; the template row (row 3) expands
into three rows, one per month, then the template row is deleted.
Development
# Install dependencies
npm install
# Compile TypeScript (outputs to ./dist)
npm run build
# Watch mode
npm run dev
# Lint
npm run lint
# Format
npm run format
Project structure
n8n-nodes-universal-templater/
├── nodes/
│ └── UniversalTemplater/
│ ├── UniversalTemplater.node.ts # Main INodeType implementation
│ ├── engines/
│ │ ├── docxEngine.ts # docxtemplater wrapper
│ │ ├── xlsxEngine.ts # ExcelJS placeholder engine
│ │ └── textEngine.ts # Handlebars wrapper
│ └── utils/
│ └── binaryHelpers.ts # Buffer ↔ IBinaryData conversion
├── index.ts # Package entry point
├── package.json
└── tsconfig.json
License
MIT