Goh is a pre-compiled template engine for the Go language that turns HTML templates into native Go functions, ranking at the top of the goTemplateBenchmark suite for rendering speed.
What is Goh?
Goh is a pre-compiled and fast template engine for Go, created by OblivionOcean and hosted on GitHub. It takes HTML template files written with a Hero-compatible syntax and generates native Go source code that renders directly into a bytes.Buffer or any io.Writer. The generated code is compiled alongside your application, so no runtime parsing or reflection is needed. The project is zero-dependency, meaning the core engine has no external libraries.
Key Features
- Pre-compiled generation — Goh parses
.htmltemplates and outputs Go source files that you compile into your binary; the benchmark shows 0 bytes allocated per operation for complex templates. - Hero-compatible syntax — Almost all statements from the Hero template engine are supported, including function definitions, template inheritance, includes, and blocks.
- Zero dependencies — The engine itself requires no third-party packages; only the optional
goimportstool is recommended during code generation. - High performance — In the included benchmark, Goh completed the complex template test in 535 ns/op with 0 B/op and 0 allocs/op, faster than Hero, Quicktemplate, and all other engines listed.
- Nine statement types — Users get function definition, inheritance, include, package import, block, raw Go code, native value, escaped value, and comment statements to control generated code.
- Auto-generated functions — Each template without a function definition statement produces no function; the last parameter of the generated function must be a
*bytes.Bufferorio.Writer, which Goh detects automatically. - Escaping built in — The escaped value statement converts variables to strings and passes them through
html.EscapeStringautomatically, preventing XSS in rendered output.
Who is it for?
- Go web developers who want to serve HTML pages with the lowest possible latency and no runtime template parsing overhead.
- Performance-sensitive teams that need to handle high request rates and can afford a compile-time code-generation step in their build pipeline.
- Developers migrating from Hero who want a nearly drop-in replacement with similar syntax and even faster rendering, as Goh states compatibility with Hero syntax.
- Library authors who need a template engine that can be embedded without pulling in external dependencies.
What can you do with Goh?
- Render server-side HTML pages: Define a function like
UserList(title string, userList []string, buffer *bytes.Buffer), call it inside anet/httphandler, and write the buffer to theResponseWriter. - Build reusable templates: Use inheritance and include statements to share a layout across pages and override blocks per view.
- Generate static or dynamic content with Go code: Insert arbitrary Go statements inside templates for loops, conditionals, and function calls, giving you the full power of the language.
- Escape user input safely: Use the escaped value statement to output variables that are automatically HTML-escaped, reducing XSS risks.
How does Goh work?
Goh runs as a command-line tool. You point it at a single .html file or a directory with -src, choose the output directory with -dest, set the generated package name with -pkg, and optionally filter extensions with -ext (default .html). It writes Go source files that must be compiled with your project. The README recommends installing goimports separately to format imports in the generated code.
The workflow is: write a template with Hero-like syntax → run Goh to generate .go files → call the generated functions from your application. The template syntax includes a function definition statement that declares the generated function's signature; the last argument must be a *bytes.Buffer or io.Writer to receive the rendered output.
Pros and cons
- Pro: Extremely fast — the complex template benchmark shows 535 ns/op and zero allocations.
- Pro: Zero-dependency engine, so it's easy to vendor and build.
- Pro: Familiar syntax for Hero users; includes inheritance, includes, and blocks.
- Con: Template file changes do not trigger automatic recompilation — the README lists this feature as not yet implemented.
- Con: It is a pre-compiled approach, so templates must be compiled into the binary, making template hot-reload impossible.
- Con: The syntax is almost (not fully) Hero-compatible, meaning edge cases may require adjustments.
Alternatives
- Hero — the original engine whose syntax Goh closely follows; benchmark shows Hero slower than Goh in both complex and simple tests.
- Quicktemplate — another precompiled Go template engine that also shows zero allocations; in the complex benchmark it scored 878 ns/op versus Goh's 535 ns/op.
- Templ — a popular Go template engine with a different code-generation approach; its complex template benchmark was 1400 ns/op.
FAQ
Is Goh free to use?
Goh is an open-source project on GitHub, so it's free to use, modify, and redistribute under its license. The README does not mention any commercial restrictions.
What is Goh's performance compared to other Go template engines?
In the benchmark results included in the README, Goh finished the complex template test in 535 ns/op with 0 bytes allocated, and the simple template test in 81.97 ns/op. It was faster than every other engine listed except the synthetic GoStaticString baseline, which just returns a constant.
Does Goh support template inheritance and includes?
Yes. Goh provides a template inheritance statement and a template include statement, along with block statements that child templates can override. This allows you to build layout hierarchies similar to those in other template engines.
Does Goh automatically recompile when templates change?
No. The README lists "Automatically re-compile after changing the template file" as an unchecked feature. You must re-run the Goh command-line tool to regenerate Go code after editing templates.
What dependencies does Goh need?
The Goh engine itself has zero dependencies. To use the generated code conveniently, the README recommends installing goimports separately, but that is not required for the core functionality.




