Template store & hot reload

The store

Templates live behind the templates.Store interface (Fetch/List/Put). The loaded store is a fallback store — a chain of sub-stores (one per loader type) tried in order — so a name resolves to the first loader that provides it.

Loading

StoreLoader.loadTemplatesMap (app/templates/fileloader/store_loader.go):

  1. loads plain templates from the templates directory using the ordered loaders (file → raw → remote-http);
  2. builds dependent loaders (compositions) that need the already-loaded store;
  3. loads compositions from the compositions directory;
  4. combines everything into the fallback store.

Per directory, loaders are tried in priority order; “not found” errors are non-fatal (try the next loader). With --templates-recursive, loading descends into nested directories, naming children parent/child.

The LazyStore seam

The internal render server needs the store to serve assets, but the store is built later in the DI graph. A LazyStore implements both StoreProvider and StoreConsumer: Wire binds one instance to both interfaces, the store loader fills it, and the internal server reads it. This is the late-binding seam that lets the graph wire up before the store exists.

Hot reload

--templates-reload-mode:

  • none — a static MapStore built once at startup (production default).
  • always — a DevStore that re-reads the template from disk on every fetch, so edits take effect without a restart (development default).

Engines & loaders

Engine dispatch (instance_loader.go) tries engines in priority order per part (body/header/footer), first match wins. Sibling loaders handle schema, params, assets, examples, and partials. The composition sub-package holds the YAML/jq and JS planners and the pdfcpu merge; the remote sub-package holds the HTTP template loader.

See Extension points to add a new engine, loader, or planner.