goTemplateBenchmark

February 16, 2026 · View on GitHub

comparing the performance of different template engines

precompilation to Go code

baseline benchmarks for comparison

  • DirectBuffer - Use go to write the HTML by hand to the buffer with basic escaping

transpiling to Go Template

  • Damsel I won't benchmark transpiling engines, because transpilation should just happen once at startup. If you cache the transpilation result, which is recommended, you would have the same performance numbers as html/template for rendering.

Why?

Just for fun. Go Templates work nice out of the box and should be used for rendering from a security point of view. If you care about performance you should cache the rendered output.

Sometimes there are templates that cannot be reasonably cached. Then you might need a really fast template engine with code generation.

How to run the benchmarks

./bench.sh -c go

Results dev machine

local desktop: ryzen 3900x

simple benchmarks

NameRunsµs/opB/opallocations/op
Ace501,4686.8961,07332
Amber829,1804.37175328
Golang829,5864.22667327
GolangText2,524,9511.4282247
Handlebars491,2897.2813,40773
JetHTML4,463,0960.78600
Mustache1,595,8212.2441,61124
Pongo21,000,0003.1592,05930
Soy1,839,7661.9681,22419

precompilation to Go code

NameRunsµs/opB/opallocations/op
Ego6,319,7100.565858
Ftmpl3,803,4550.92977412
Goh41,145,1360.08400
Gomponents2,234,0621.60777625
Gorazor7,170,6800.5015125
HB1,387,5572.5992,06444
Hero31,017,6280.12500
Jade25,551,1210.14000
Quicktemplate19,508,5100.18100
Templ4,734,1410.76018210

more complex test with template inheritance (if possible)

NameRunsµs/opB/opallocations/op
ComplexGolang99,99036.0245,474209
ComplexGolangText214,26016.7022,39678
ComplexJetHTML462,3127.6125355
ComplexMustache248,39214.3136,730112

precompilation to Go code

NameRunsµs/opB/opallocations/op
ComplexEgo1,275,1142.81556931
ComplexFtmpl856,6274.1373,53538
ComplexGoDirectBuffer5,595,3930.65600
ComplexGoh6,029,9590.59300
ComplexGorazor1,000,0003.2833,68824
ComplexHero3,601,7051.00300
ComplexJade3,236,3321.06000
ComplexQuicktemplate3,428,4791.03300
ComplexTempl1,000,0003.16876238

Security

All packages assume that template authors are trusted. If you allow custom templates you have to sanitize your user input e.g. bluemonday. Generally speaking I would suggest to sanitize every input not just HTML-input.

Attention: This part is not updated since 2016.

FrameworkSecurityComment
AceNo
amberNo
egoPartial (html.EscapeString)only HTML, others need to be called manually
egonPartial (html.EscapeString)only HTML, others need to be called manually
egonslinsoPartial (html.EscapeString)only HTML, others need to be called manually
ftmplPartial (html.EscapeString)only HTML, others need to be called manually
GoYescontextual escaping html/template Security Model
GorazorPartial (template.HTMLEscapeString)only HTML, others need to be called manually
HandlebarsPartial (raymond.escape)only HTML
HeroPartial (html.EscapeString)only HTML, others need to be called manually
JadePartial (html.EscapeString)Autoescape for HTML, others need to be called manually
JetPartial (html.EscapeString)Autoescape for HTML, others need to be called manually
KasiaPartial (kasia.WriteEscapedHtml)only HTML
MustachePartial (template.HTMLEscape)only HTML
Pongo2Partial (pongo2.filterEscape, pongo2.filterEscapejs)autoescape only escapes HTML, others could be implemented as pongo filters
QuicktemplatePartial (html.EscapeString)only HTML, others need to be called manually
SoyPartial (template.HTMLEscapeString, url.QueryEscape, template.JSEscapeString)autoescape only escapes HTML, contextual escaping is defined as a project goal