Skip to main content
Copper renders server-side HTML using Go templates. Layouts, pages, and partials are all embedded into your binary.
New projects default to a React frontend with Inertia; see Frontend. This page covers classic server-rendered Go templates, which are a great fit for simpler apps and HTMX-style interactivity.

Template Directory

Templates live under web/src in three conventional directories:
A layout defines the shell and renders the page inside it:
web/src/layouts/main.html
web/src/pages/rocket.html

Rendering Pages

Copper provides chttp.HTMLReaderWriter for writing HTML responses. Inject it into your router and call WriteHTML:
LayoutTemplate defaults to main.html and StatusCode to 200; you may set either explicitly when needed. On errors, an appropriate page will automatically be chosen for you: internal-error.html for 500s and not-found.html for 404s.

Template Functions

Every template has the full Sprig function library available, including upper, date, and mustToRawJson. You may add your own functions using chttp.HTMLRenderFunc. Since render funcs receive the current request, they can expose per-request state such as the signed-in user:
web/wire.go

Partials

Partials in web/src/partials are reusable fragments. Render one inside any template with the built-in partial function:
You may also write a partial directly as a response, which works well for HTMX-style updates that swap a fragment into the page:

Static Assets

Files in web/public are served under /static/. For example, web/public/logo.svg is available at /static/logo.svg. In production these files are embedded into your binary, while in development they are read from disk.

Local Development

Two config flags make template development pleasant, and both are enabled in config/dev.toml for new projects:

Single-Page Apps

If your frontend handles its own routing, you may configure every unmatched GET request to render index.html:

API-Only Apps

If your application doesn’t serve HTML at all, use chttp.WireModuleEmptyHTML in place of the HTML and static dir bindings; it satisfies wire with empty stand-ins. Projects created with -frontend=none are configured this way.