Generated Code

templ generate writes one *_templ.go per .templ file. Reading what is inside explains templ’s runtime behavior: why it is fast, why the LSP works, and why you must regenerate.

What is in the file

A component becomes a function returning a templruntime.GeneratedTemplate (simplified from real generated output):

func hello(name string) templ.Component {
    return templruntime.GeneratedTemplate(func(
        in templruntime.GeneratedComponentInput,
    ) (err error) {
        buf, isNew := templruntime.GetBuffer(in.Writer) // pooled buffer
        if !isNew {
            defer func() { err = templruntime.ReleaseBuffer(buf) }()
        }
        // static HTML: written as a constant at a fixed position index
        err = templruntime.WriteString(buf, 1, "<h1>Hello, ")
        if err != nil {
            return err
        }
        // { name } here: escaped, then written to the same buffer
        _ = name
        return nil
    })
}

The mechanisms that matter, all visible in generated files:

  1. Buffer pooling - templruntime.GetBuffer / ReleaseBuffer recycle render buffers across requests, avoiding per-request allocations
  2. Static HTML as constants - markup literals become string constants written via templruntime.WriteString(buffer, positionIndex, "constant")
  3. Position indexes - the index maps output back to .templ source lines; this is what powers LSP diagnostics and source maps
  4. Version stamp - a templ version string is baked into each generated file unless you pass -include-version=false, so stale files are detectable

What this buys you

  • Compile-time checking - components have typed parameters; wrong arguments fail the build
  • Zero parse at runtime - no template registry, nothing to parse on boot
  • Render errors are Go errors - Render returns an error you handle like any other
  • No reflection on the render path - output is plain write calls

The cost

Gotcha: Generated files must be regenerated when .templ files change. A stale *_templ.go compiles fine and silently serves old markup - this is the most common templ surprise. Run templ generate --watch in development.

Static generation

Render accepts any writer, so build-time generation is a loop over routes into files:

for route, component := range routes {
    f, _ := os.Create("public/" + route)
    component.Render(ctx, f)
    f.Close()
}

Pair with go:embed to ship a fully static site inside one binary; handlers then only serve dynamic endpoints. templ’s docs cover this mode under static rendering.

Versus html/template

Aspecttemplhtml/template
Parse stepNone - output is compiled codeParse templates at runtime
IndirectionDirect function callstemplate.FuncMap lookups
Type errorsCompile timeRuntime
Updating markupRegenerate and rebuildReload template files

The trade in one line: templ moves template work from request time to build time, and charges you a regeneration step for it. See also Rendering Model.