Template author workflow

The loop you actually work in: scaffold a template, iterate with hot reload and the tester UI, validate in CI, build your image, deploy.

You use PDF Server as a base image: you write templates and schemas, test them, and ship your own image. Here is the development cycle that supports that.

1. Scaffold a template

Create a directory under your templates/ folder. The minimum is a body template; add schema, params, assets, partials, and examples as needed.

templates/
  invoice/
    template.handlebars     # body (required)
    schema.json             # validate request data
    params.json             # PDF options (margins, format, …)
    examples/
      sample.json           # example dataset for the tester + CI

See Your first template and Template structure.

2. Iterate with hot reload + the tester UI

Run the server against your templates with reload mode always so edits take effect without a restart:

docker run --rm -it -p 9999:9999 \
  -e TEMPLATES_RELOAD_MODE=always \
  -v "$PWD/templates:/templates" \
  registry.gitlab.com/c0va23/pdf-server:latest-chromium

Then open http://localhost:9999/ and use the tester UI: pick your template, paste or load example data, and preview the rendered PDF. Edit the template file, re-render — the change is live. See Tester UI.

The examples/*.json datasets you commit show up in the tester and are what CI renders, so they double as fixtures and documentation.

3. Validate before you ship

The validate subcommand parses every template and renders every example, exiting non-zero on any failure. Wire it into CI so a broken template fails the build:

pdf-server validate \
  --templates-dir ./templates \
  --compositions-dir ./compositions

Filter to a subset while iterating:

pdf-server validate invoice/sample

4. Build your image

Layer your templates onto the base image:

ARG PDF_SERVER_IMAGE=registry.gitlab.com/c0va23/pdf-server:latest-chromium
FROM ${PDF_SERVER_IMAGE}
ADD templates templates
ADD compositions compositions

See Build your image for the full deployment story (Chromium vs Firefox, recursive templates, compositions).

5. Deploy and operate

Run the image on your infrastructure behind your own auth/proxy. Tune the browser pool, timeouts, and factory mode for your load, and turn on tracing if you use OpenTelemetry. See Operations and Tuning.

The loop, in short

scaffold → run with reload + tester UI → edit/preview → validate → build image → deploy

Everything except the final deploy runs locally with a single container and no rebuilds.