FAQ and troubleshooting
Answers to the questions that come up in practice. Each one reflects the actual implementation; where a limitation exists, it is stated rather than papered over.
Is this a new template language?
Section titled “Is this a new template language?”No. templator is a thin wrapper around html/template. Templates are
plain .html files with standard {{...}} syntax, contextual
auto-escaping works unchanged, and everything you know about
html/template applies. The wrapper contributes the type-safe data layer
(the type-safety model), the
registry lifecycle, and validation.
How do I share layouts or partials across files?
Section titled “How do I share layouts or partials across files?”Not across files — each template is parsed standalone
(template.New(name).Parse(content)), so {{template "partial.html"}}
cannot resolve to a definition in another file, and cross-file includes
will fail at render time. What works:
- Same-file composition:
{{define "part"}}...{{end}}plus{{template "part"}}inside one template file is fine. - Handler-level composition: render a partial into an
io.Pipe(or buffer) and pass it into your page data as ordinary data.
A broader layout mechanism would need explicit associations between
templates, which the current Registry.Get model does not define. If
layouts are a big part of your app, factor them into your Handler usage
rather than waiting for a feature here.
Can templator serve HTTP routes directly?
Section titled “Can templator serve HTTP routes directly?”There is no router — by design, Execute(ctx, w, data) maps onto
http.HandlerFunc in one line, as shown in Registry and
handlers. Compose it
with net/http, http.ServeMux patterns, or any middleware chain of your
choice.
Is rendering concurrent-safe and fast?
Section titled “Is rendering concurrent-safe and fast?”Yes. Handlers are parsed once per registry, guarded by a mutex with
double-checked locking, and rendering adds no locks at all — concurrent
Execute calls run in parallel, since html/template itself supports
concurrent execution of parsed templates. The measured overhead of templator
is one Write wrapper per write, plus context checks. For throughput
design, one registry for the process lifetime + per-request Execute is
the pattern; per-request NewRegistry would forfeit the parse cache.
What happens when the render dies halfway?
Section titled “What happens when the render dies halfway?”Two guarantees and one caveat. Guaranteed: the error is
ErrTemplateExecution with the template name and cause, and the context is
re-checked after rendering. The caveat: cancellation is checked at write
boundaries, so some output may already have been written when the call
fails — an HTTP response may have flushed bytes. Long templates render too
fast for this to matter in practice; if cancellation responsiveness is
critical for your workload, keep templates small or chunk writes
deliberately.
I got an error at Get, not at Execute. Is that expected?
Section titled “I got an error at Get, not at Execute. Is that expected?”Yes — lazy loading. NewRegistry performs no I/O; each template is read,
validated, and parsed at first Get. A parse error, a missing file, or a
validation failure therefore surfaces at Get calls, which typically
happen at startup or first render — see Errors.
Why does validation miss my field reference?
Section titled “Why does validation miss my field reference?”The validator checks three whole-action shapes only: {{.Field}},
{{ .A.B }}, and {{if .Field}}. References inside other actions —
{{range .Items}}, pipelines such as {{.Title | upper}}, includes — are
not extracted, so a template using only those passes validation unhindered.
More importantly, the check has real limits beyond plain struct fields:
a call like {{.Footer}} where Footer is a method is wrongfully
rejected, and a path like {{.Meta.Key}} through a map field currently
panics the load. In short, validation is dependable for exported struct
fields, nested structs, and pointer chains — drop
WithFieldValidation for templates that call methods or walk into maps.
The full list is in Field validation.
Can I use one data type for all templates?
Section titled “Can I use one data type for all templates?”You can, but the type system will not help you any more than plain
html/template would. The intended split is one registry per data shape —
HomeData, AboutData — so each template’s contract is its own type.
That is exactly what the compile-time guarantee is for.
Where do I report bugs?
Section titled “Where do I report bugs?”In the templator issue tracker. For docs problems, open an issue on templator-docs instead.