Template reload modes
When you run PDF Server as the base for your own PDF service, its templates live in a directory you control. Reload mode decides whether — and how — the server notices edits to that directory after it has started. It is set with a single flag:
--templates-reload-mode <none|always|watch> # env TEMPLATES_RELOAD_MODE
The default is none. There are three modes.
At a glance
| Mode | Picks up edits without restart | New/removed templates in listings | Tester UI auto-refreshes | Per-request overhead | Run it for |
|---|---|---|---|---|---|
none (default) | ✗ | ✗ | ✗ | none | Production — templates baked into your image |
always | ✓ | ✓ | ✗ (re-render to see changes) | disk read per render | Templates that change out of band (a mounted volume) |
watch | ✓ | ✓ | ✓ (over SSE) | none between rebuilds | Interactive authoring with the tester UI |
none — static snapshot (production default)
Templates are read once at startup into an immutable store and never re-read. Changing a file on disk has no effect until you restart the server.
This is the right mode for a deployed service: your templates are baked into your image (see Build your image), so they never change under a running process, and every render serves from memory with no disk access.
always — re-read on every render
Each render re-reads its template from disk, and template listings (the tester menu, the OpenAPI spec) re-scan the directory — so files you add, edit, or remove after startup are reflected without a restart. Nothing is pushed to the browser, so an open tester UI does not refresh on its own: re-render (or reload the page) to pick up a change.
Use always when the templates directory changes independently of the process —
for example a volume you mount and update, or a filesystem where the watch
mode's change notifications don't work (some network and overlay filesystems).
The cost is a disk read per render; on local SSDs it is negligible, but it is not
free at high throughput, which is why production uses none.
watch — live reload with the tester UI
The server watches the template and composition directories for filesystem changes, rebuilds the whole store when it sees one, and atomically swaps the new store in. A rebuild that fails (for example a half-written file mid-save) keeps the previous store, so a bad intermediate edit never takes the service down.
On top of that, watch mounts GET /_events and pushes a change event to
connected tester UIs over Server-Sent Events. The tester refreshes its template
menu and re-renders the current preview automatically — edit a file, and the
preview updates with no click. Between rebuilds, renders serve from the built
store just like none, so there is no per-render disk cost.
A burst of file events (an editor rewriting several files) is collapsed into one
rebuild by a debounce window, --templates-reload-debounce (default 250ms).
Two caveats:
- A top-level templates or compositions directory that does not exist at startup is not watched if you create it later — restart the server once after creating it. Existing directories and any nesting beneath them are picked up live.
- If change notifications are unreliable on your filesystem (some network/overlay
mounts), use
alwaysinstead.
The first build is the strict one
Whatever the mode, the store is built once at startup and a template that
cannot be loaded fails that build — the process logs the reason and exits,
serving nothing. A rebuild is not strict in the same way: in watch mode a
failed rebuild keeps the previous store and logs a warning, so the running
service is never taken down by an edit.
The asymmetry is about when, not about the mode, and the case it catches you on is ordinary: create a template directory, and until you have written the body file in it there is no template there. The message names the file it wanted —
no template file in this directory: expected one of template.mustache,
template.handlebars, template.tmpl, template.html
— but docker run --rm -d deletes the container before anyone reads it, so it
presents as a container that silently refuses to exist. Run it in the
foreground (drop -d), or check the templates directory ahead of time with
pdf-server validate, which answers the same question
and prints it.
Choosing a mode
- Production:
none. Templates are fixed in your image; take the fast path. - Authoring locally with the tester UI:
watch, for hands-off live preview. - Templates change under a running server (mounted/synced volume) or
watchcan't see changes on your filesystem:always.
See also
- Template author workflow — the full edit → preview → validate → ship loop these modes support.
- Tester UI — the live-reload consumer of
watch. - CLI & configuration —
--templates-reload-mode,--templates-reload-debounce, and--sse-subscriber-buffer. - Template store & hot reload — how the store, the swap, and the watcher work internally.