Template data and helpers
The placeholders, linked records and formatting helpers available inside a PDF template.
A template mixes fixed layout with {{placeholders}} that are filled in when the document is made. This page lists the data and helpers you can use.
How placeholders work
- Placeholders use double curly braces, for example
{{.org.name}}. - Conditions and loops use
{{if …}}…{{end}}and{{range …}}…{{end}}. - Values are always escaped. A company called
R&D <Ltd>prints exactly like that and can never break your layout. - A placeholder that is not written correctly is refused when you save, with a message from the template language.
Data you can use
| Placeholder | What it holds |
|---|---|
{{.org.name}} |
Your workspace name. |
{{.org.default_currency}} |
The workspace default currency code, for example INR. |
{{.now}} |
The moment the document is made. Use it with {{date .now}}. |
{{.record.values.<field>}} |
A field of the record, by its field key, for example {{.record.values.number}}. |
{{.record.id}}, {{.record.type}}, {{.record.created_at}} |
The record's id, type key and creation time. |
{{.refs.<field>.values.<field>}} |
A record linked through a reference field, for example {{.refs.customer.values.name}}. |
{{.data}} |
Extra data passed in by a function. Empty when you generate from the Documents tab. |
.record and .refs exist only when a record is used. Guard them with {{if .record}} and {{if .refs.customer}} so the template also works without one.
Linked records
- Each reference field on the record type is resolved one level deep. A field that links to many records (
refs) gives a list you loop over with{{range .refs.items}}. - A linked record you are not allowed to read, or one that no longer exists, is skipped. Guard with
{{if}}. - Up to 50 linked records are loaded for one document.
Permissions and masked fields
Documents are built with the permissions of the person generating them. A field that person cannot see is not available to the template, so it does not appear on the PDF.
Helpers
| Helper | Example | Result |
|---|---|---|
money |
{{money .record.values.total .org.default_currency}} |
1,234.50 INR. Thousands separators, two decimals (extra decimals are cut, not rounded), currency code appended. Text that is not a number is printed as it is, with the currency code after it. |
date |
{{date .record.created_at}} |
Jan 2, 2026. |
datetime |
{{datetime .now}} |
Jan 2, 2026 15:04. |
upper |
{{upper .record.values.name}} |
Upper case. |
lower |
{{lower .record.values.name}} |
Lower case. |
date and datetime understand stored date values; anything they cannot read is printed unchanged. The standard template tools such as printf, index, and, or, eq and len also work.
Page numbers
{page} and {pages} (single braces) work only inside <header> and <footer>. Example: Page {page} of {pages}.
Images
Images must be embedded as base64 data: addresses (PNG, JPEG or GIF). Web links are not fetched. See Layout reference.
Example: line items
{{range $k, $v := .record.values}}
<tr><td>{{$k}}</td><td>{{$v}}</td></tr>
{{end}}
This prints one table row per field of the record. It is the loop in the starter layout.