The n8n node
Templates
A template is HTML with Handlebars variables. pdfmill ships five polished starters you can render by id, and the dashboard editor lets you build your own with a live preview.
Built-in starter templates
These render by id through Generate from Template — they are what the node's template dropdown lists. Each is internationalisation-safe (the render image bakes the full Noto font pack, including CJK and emoji). Unknown or missing variables render blank rather than crashing, so a partial payload still produces a document.
| Template id | Purpose | Variables |
|---|---|---|
invoice | Line items, totals, tax, and billing details. | invoiceNumber, issuedAt, dueAt, paymentTerms, currency, from.{name,address,email,taxId}, billTo.{name,address,email}, items[].{description,quantity,unitPrice,lineTotal}, subtotal, taxRate, taxAmount, total, notes |
quote | A sales quote with optional discount and terms. | quoteNumber, issuedAt, validUntil, currency, preparedBy, from.{name,address,email}, prospect.{name,company,address}, items[].{description,quantity,unitPrice,lineTotal}, subtotal, discountRate, discountAmount, total, terms[] |
report | A period report with KPIs, sections, and a comparison table. | kicker, title, subtitle, periodStart, periodEnd, generatedAt, author, summary, kpis[].{label,value,delta,down}, sections[].{heading,body}, table.caption, table.rows[].{label,current,previous,change,direction} |
certificate | A landscape award / completion certificate. | certificateNumber, organization, recipientName, programName, hours, grade, completedAt, issuedAt, issuerName, issuerTitle |
packing-slip | A shipment packing slip with line items and totals. | orderNumber, orderedAt, shippedAt, carrier, trackingNumber, shipFrom.{name,address}, shipTo.{name,address}, items[].{sku,description,quantity}, totalItems, totalWeight, notes |
Writing template HTML with Handlebars
Templates are full HTML documents with inline CSS (use @page for print margins and size). Values come from the node's Data field:
{{variable}}is HTML-escaped;{{{variable}}}emits raw HTML (use only for content you trust).- Nested paths (
{{from.name}}) and iteration ({{#each items}} … {{/each}}) work as usual. - A missing variable renders as an empty string — never an error.
Two deterministic helpers are available (no locale or timezone surprises across machines):
{{formatDate value "iso|medium|long"}}— formats a date in UTC, English.mediumis the default (e.g.15 Jul 2026).{{formatMoney value "USD"}}— a currency symbol plus thousands separators (e.g.$3,363.50); zero-decimal currencies like JPY are handled.
<!-- Escaped by default; use triple-stache for trusted raw HTML -->
<h1>{{title}}</h1>
<!-- Nested paths and iteration -->
<p>Bill to {{billTo.name}}</p>
{{#each items}}
<tr><td>{{this.description}}</td><td>{{this.quantity}}</td></tr>
{{/each}}
<!-- Deterministic helpers -->
<p>Issued {{formatDate issuedAt "long"}}</p>
<p>Total {{formatMoney total currency}}</p>Your own templates
Build custom templates in the dashboard's Templates editor: write HTML + Handlebars on the left, edit sample data, and see a live PDF preview on the right. Templates are versioned and are your IP — encrypted at rest and exportable.
Using a custom template from n8n today
{{variables}} are filled from Data exactly the same way. Rendering custom templates by id through the API is on the roadmap.Ready-made n8n workflows for each starter — payment → invoice, row → certificate, form → report, and more — ship as importable gallery workflows. See the quickstart to render your first one.