Template helpers
The Handlebars and Go template engines provide built-in helpers. Mustache and static templates do not.
Live examples: the helpers_handlebars, helpers_go_template, and
format_date templates in the Gallery.
What no helper provides is arithmetic or number formatting. Nothing here adds two values, multiplies a quantity by a price, or renders a number as currency: the helpers below format dates, embed files, and render markdown, and that is the whole set. Compute derived values before you send the data — see Template authoring.
The Go engine is the exception, and only for formatting: html/template ships
Go's own built-ins, so printf "%.2f" is available there without a helper. See
Formatting numbers.
format_time
Formats an ISO-8601 timestamp using a strftime pattern. It accepts every conversion in the specifier reference below.
{{/* Go — positional or piped */}}
{{format_time "%Y-%m-%dT%H:%M:%S%z" .from_time}}
{{.from_time | format_time "%Y-%m-%dT%H:%M:%S%z"}}
Accepted input
The input must be a full RFC 3339 timestamp — a timezone is required, fractional
seconds are optional (2020-12-12T12:12:12Z, 2020-12-12T15:12:12.5+03:00).
Anything else — a bare YYYY-MM-DD date, a timestamp with a space instead of
T, or a locale date like 12/31/2025 — is rejected. To format a date without
a time, use format_date.
In Handlebars a bad input surfaces as a helper error; in Go it returns an error from the pipeline.
format_date
Formats an ISO 8601 calendar date (YYYY-MM-DD) using a
strftime pattern. Use it for date
fields that carry no time; for full timestamps use format_time.
{{/* Go — positional or piped */}}
{{format_date "%d.%m.%Y" .issued_on}}
{{.issued_on | format_date "%d.%m.%Y"}}
The input must be a bare YYYY-MM-DD date (2025-12-12). Anything carrying a
time part — an RFC 3339 timestamp, or a date with a trailing time — is rejected;
pass those to format_time instead. This matches the JSON-schema date format,
so a field declared "format": "date" in a template's schema.json is always a
valid format_date input.
The pattern may use only the date conversions — the rows marked ✓ in the
specifier reference below — each optionally with the
%-/%# no-padding flag. Any time or zone specifier (%H, %z, …) or unknown
conversion is rejected rather than emitting a meaningless 00:00:00, since a
date has no time.
Conversion specifiers
Both helpers share strftime's conversion set. format_time accepts all of it;
format_date accepts only the rows marked ✓ in the Date column (plus the
%-/%# no-padding flag on any of them). The Example column shows the
output for Wednesday, 6 August 2025, 14:05:06 in a +02:00 (CEST) zone.
| Specifier | Meaning | Example | Date |
|---|---|---|---|
%Y | Year with century | 2025 | ✓ |
%y | Year without century (00–99) | 25 | ✓ |
%C | Century (year ÷ 100) | 20 | ✓ |
%G | ISO 8601 week-based year | 2025 | ✓ |
%g | ISO week-based year without century | 25 | ✓ |
%m | Month number (01–12) | 08 | ✓ |
%B | Full month name | August | ✓ |
%b, %h | Abbreviated month name | Aug | ✓ |
%d | Day of month, zero-padded (01–31) | 06 | ✓ |
%e | Day of month, space-padded | · 6 | ✓ |
%j | Day of year (001–366) | 218 | ✓ |
%A | Full weekday name | Wednesday | ✓ |
%a | Abbreviated weekday name | Wed | ✓ |
%u | Weekday, Monday 1 … Sunday 7 | 3 | ✓ |
%w | Weekday, Sunday 0 … Saturday 6 | 3 | ✓ |
%U | Week of year, Sunday first (00–53) | 31 | ✓ |
%W | Week of year, Monday first (00–53) | 31 | ✓ |
%V | ISO 8601 week of year (01–53) | 32 | ✓ |
%D | Date as %m/%d/%y | 08/06/25 | ✓ |
%F | Date as %Y-%m-%d | 2025-08-06 | ✓ |
%v | Date as %e-%b-%Y | · 6-Aug-2025 | ✓ |
%x | Locale date (%m/%d/%y) | 08/06/25 | ✓ |
%H | Hour, 24-hour, zero-padded (00–23) | 14 | |
%k | Hour, 24-hour, space-padded | 14 | |
%I | Hour, 12-hour, zero-padded (01–12) | 02 | |
%l | Hour, 12-hour, space-padded | · 2 | |
%M | Minute (00–59) | 05 | |
%S | Second (00–60) | 06 | |
%p | AM/PM | PM | |
%R | Time as %H:%M | 14:05 | |
%r | Time as %I:%M:%S %p | 02:05:06 PM | |
%T | Time as %H:%M:%S | 14:05:06 | |
%X | Locale time (%H:%M:%S) | 14:05:06 | |
%c | Locale date and time | Wed Aug ·6 14:05:06 2025 | |
%Z | Time-zone name | CEST | |
%z | Time-zone offset from UTC | +0200 | |
%n | Newline | \n | ✓ |
%t | Tab | \t | ✓ |
%% | Literal % | % | ✓ |
A · marks a padding space. Any numeric conversion may take the glibc %- or
Windows %# flag to drop that padding — %-d → 6 instead of 06. The flag
is valid wherever its conversion is, so format_date takes %-d but still
rejects %-H. There are no E/O locale modifiers; %c, %x, and %X use
the C locale.
markdown
Renders a Markdown string to HTML and returns it as safe (unescaped) HTML.
{{markdown .description}}
{{.description | markdown}}
Security:
markdownoutput is not HTML-escaped, and the renderer does not strip embedded HTML. Never pass untrusted data tomarkdownwithout sanitising it. See Security model.
embed_text
Reads a file from the template's assets/ directory and inlines its text
content — handy for inlining CSS.
The content is inlined as-is, with double braces: escaping it would be
destroying it, since a stylesheet whose quotes came back as ' no longer
parses as CSS — the browser drops the declaration and paints the page in its
own defaults, with nothing reported. Go templates escape by context, so there
embed_text returns the type matching the file's extension (.css, .js,
otherwise HTML) and it lands unescaped in the element it was written into.
Security: the same property that keeps the CSS intact means
embed_textemits raw content. The path names a file the template author shipped — never build it from request data.
embed_base64
Reads an asset and returns its base64 encoding — handy for inlining images as data URIs.
Paths are relative to the template's assets/ directory.
equal (Handlebars only)
A block helper that renders its block when two stringified values are equal, with
an {{else}} inverse.
Helper availability
| Helper | Handlebars | Go | Mustache | Static |
|---|---|---|---|---|
format_time | ✓ | ✓ | ||
format_date | ✓ | ✓ | ||
markdown | ✓ | ✓ | ||
embed_text | ✓ | ✓ | ||
embed_base64 | ✓ | ✓ | ||
equal | ✓ |