comparing the performance of different template engines
- 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.
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 possibly need a really fast template engine with code generation.
Changed the environment to my local dev laptop: i7-6700T 16GB Mem
Golang: 1.8
Name |
Runs |
µs/op |
B/op |
allocations/op |
Ace |
300,000 |
16.360 |
5,210 |
77 |
Amber |
1,000,000 |
5.743 |
1,448 |
39 |
Golang |
1,000,000 |
5.388 |
1,368 |
38 |
Handlebars |
300,000 |
11.100 |
4,258 |
90 |
JetHTML |
3,000,000 |
1.261 |
0 |
0 |
Kasia |
1,000,000 |
3.322 |
1,192 |
26 |
Mustache |
1,000,000 |
3.618 |
1,568 |
28 |
Pongo2 |
1,000,000 |
5.122 |
2,376 |
47 |
Soy |
1,000,000 |
3.474 |
1,384 |
26 |
Name |
Runs |
µs/op |
B/op |
allocations/op |
Ego |
5,000,000 |
0.975 |
85 |
8 |
Egon |
2,000,000 |
2.220 |
309 |
22 |
EgonSlinso |
10,000,000 |
0.394 |
0 |
0 |
Ftmpl |
3,000,000 |
1.527 |
1,141 |
12 |
Gorazor |
3,000,000 |
1.264 |
613 |
11 |
Hero |
20,000,000 |
0.212 |
0 |
0 |
Quicktemplate |
20,000,000 |
0.354 |
0 |
0 |
Name |
Runs |
µs/op |
B/op |
allocations/op |
ComplexEgo |
1,000,000 |
4.353 |
656 |
41 |
ComplexEgoSlinso |
2,000,000 |
1.984 |
165 |
7 |
ComplexEgon |
500,000 |
9.260 |
1,617 |
101 |
ComplexFtmpl |
1,000,000 |
6.513 |
5,043 |
48 |
ComplexFtmplInclude |
1,000,000 |
6.347 |
5,043 |
48 |
ComplexGolang |
100,000 |
43.811 |
10,535 |
300 |
ComplexGorazor |
500,000 |
9.585 |
8,453 |
73 |
ComplexHero |
3,000,000 |
1.427 |
0 |
0 |
ComplexJetHTML |
500,000 |
9.958 |
546 |
5 |
ComplexMustache |
200,000 |
21.787 |
7,854 |
166 |
ComplexQuicktemplate |
2,000,000 |
1.908 |
0 |
0 |
single CPU, 1GB RAM
Golang: 1.8
Name |
Runs |
µs/op |
B/op |
allocations/op |
Ace |
20,000 |
107.627 |
5,208 |
77 |
Amber |
30,000 |
37.748 |
1,448 |
39 |
Golang |
30,000 |
41.577 |
1,368 |
38 |
Handlebars |
20,000 |
64.995 |
4,256 |
90 |
JetHTML |
200,000 |
7.530 |
0 |
0 |
Kasia |
100,000 |
19.165 |
1,192 |
26 |
Mustache |
100,000 |
19.828 |
1,568 |
28 |
Pongo2 |
100,000 |
44.673 |
2,376 |
47 |
Soy |
100,000 |
18.591 |
1,384 |
26 |
Name |
Runs |
µs/op |
B/op |
allocations/op |
Ego |
1,000,000 |
4.810 |
85 |
8 |
Egon |
200,000 |
10.859 |
309 |
22 |
EgonSlinso |
1,000,000 |
1.894 |
0 |
0 |
Ftmpl |
200,000 |
9.350 |
1,141 |
12 |
Gorazor |
200,000 |
7.134 |
613 |
11 |
Hero |
1,000,000 |
1.252 |
0 |
0 |
Quicktemplate |
1,000,000 |
1.406 |
0 |
0 |
Name |
Runs |
µs/op |
B/op |
allocations/op |
ComplexEgo |
100,000 |
25.522 |
656 |
41 |
ComplexEgoSlinso |
200,000 |
10.051 |
165 |
7 |
ComplexEgon |
30,000 |
48.603 |
1,616 |
101 |
ComplexFtmpl |
50,000 |
38.582 |
5,040 |
48 |
ComplexFtmplInclude |
30,000 |
46.322 |
5,040 |
48 |
ComplexGolang |
10,000 |
298.372 |
10,531 |
300 |
ComplexGorazor |
20,000 |
70.508 |
8,449 |
73 |
ComplexHero |
200,000 |
8.085 |
0 |
0 |
ComplexJetHTML |
30,000 |
66.645 |
544 |
5 |
ComplexMustache |
10,000 |
141.660 |
7,849 |
166 |
ComplexQuicktemplate |
300,000 |
10.346 |
0 |
0 |
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.
Framework |
Security |
Comment |
Ace |
No |
|
amber |
No |
|
ego |
Partial (html.EscapeString) |
only HTML, others need to be called manually |
egon |
Partial (html.EscapeString) |
only HTML, others need to be called manually |
egonslinso |
Partial (html.EscapeString) |
only HTML, others need to be called manually |
ftmpl |
Partial (html.EscapeString) |
only HTML, others need to be called manually |
Go |
Yes |
contextual escaping html/template Security Model |
Gorazor |
Partial (template.HTMLEscapeString) |
only HTML, others need to be called manually |
Handlebars |
Partial (raymond.escape) |
only HTML |
Hero |
Partial (html.EscapeString) |
only HTML, others need to be called manually |
Jet |
Partial (html.EscapeString) |
Autoescape for HTML, others need to be called manually |
Kasia |
Partial (kasia.WriteEscapedHtml) |
only HTML |
Mustache |
Partial (template.HTMLEscape) |
only HTML |
Pongo2 |
Partial (pongo2.filterEscape, pongo2.filterEscapejs) |
autoescape only escapes HTML, others could be implemented as pongo filters |
Quicktemplate |
Partial (html.EscapeString) |
only HTML, others need to be called manually |
Soy |
Partial (template.HTMLEscapeString, url.QueryEscape, template.JSEscapeString) |
autoescape only escapes HTML, contextual escaping is defined as a project goal |