Skip to content

Benchmarks ​

These benchmarks are not intended to say one library is better than another, only to provide some rough idea of performance as a reference.

To reproduce these tables:

sh
pnpm bench            # the tables below
pnpm bench:vs [rev]   # this working tree against another revision, to check a change
pnpm bench:size       # bytes emitted rather than time

All benchmark data below was produced on a base-model M5 Macbook Air

Relative speed ​

@itsy/html is 1.00 in every column. Higher is faster, meaning 1.33 is a third faster and 0.25 is four times slower.

rendererone <a>one elementnested page1000 rowsescape-heavyoverall
no escaping9.343.942.541.95428.879.51
hand-written1.431.421.001.171.091.21
@itsy/html1.001.001.001.001.001.00
hono/html0.740.760.580.690.810.71
ghtml0.720.780.570.670.830.71
htm + preact-render-to-string0.340.280.280.251.230.39
lit + @lit-labs/ssr0.170.180.150.170.460.20

Absolute time per render ​

Lower is faster.

rendererone <a>one elementnested page1000 rowsescape-heavy
no escaping12.1 ns44.3 ns0.96 µs102 µs0.01 µs
hand-written78.5 ns123 ns2.45 µs168 µs2.15 µs
@itsy/html113 ns174 ns2.45 µs198 µs2.35 µs
hono/html153 ns230 ns4.22 µs286 µs2.92 µs
ghtml156 ns224 ns4.28 µs296 µs2.83 µs
htm + preact-render-to-string330 ns613 ns8.66 µs780 µs1.92 µs
lit + @lit-labs/ssr657 ns953 ns16.3 µs1195 µs5.09 µs

html vs trusted performance ​

trusted is a more performant export that removes escaping

rendererone <a>one elementnested page1000 rowsplain textoverall
no escaping5.912.771.911.558.983.37
@itsy/html trusted2.121.621.711.482.531.86
hand-written2.262.001.301.341.721.69
@itsy/html1.001.001.001.001.001.00
rendererone <a>one elementnested page1000 rowsplain text
no escaping12.4 ns44.8 ns0.90 µs96.5 µs6.06 ns
@itsy/html trusted34.7 ns76.6 ns1.00 µs101 µs21.5 ns
hand-written32.5 ns61.9 ns1.31 µs112 µs31.7 ns
@itsy/html73.5 ns124 ns1.71 µs150 µs54.4 ns

Benchmark test descriptions ​

Rendered from a list of 1000 products whose names hold & and ", and whose links hold & — ordinary data that still has to be escaped.

columnwhat it renders
one <a>a single link: one URL attribute, one class, one text value
one elementone <article> with five values in it, no URL attribute
nested pagea nav and a list, built from templates nested three deep
1000 rowsa table, 1000 rows of four cells, each row nesting a link template
escape-heavy760 characters of nothing but <, >, &, " and '

The escape-heavy column is the worst case for an escaper, not a realistic page. Text with nothing to escape should be the fastest path for every renderer.

The two reference points ​

hand-written is a plain template literal with an esc() call around each value, using the same escaper @itsy/html uses. It has no scanner, no context, no URL guard and allocates no Html, so it is the 'speed floor' and not a typical performance example.

no escaping is the same template literal with the esc() calls taken out. It is meant to be a reference for the absolute fastest the test machine is performing at.

MIT licensed.