N/ NIFT LABS

Template engines / document assembly

One template.
New data.
Exact output.

Five engines assemble the same documents. What does preparation cost—and what happens when the next render arrives?

ASSEMBLY / 001BYTE CONTRACT
01 / TEMPLATE<h1>$[d.title]</h1>
@input('footer')
02 / DATA{ title: "Template lab",
 author: { name: "Nick" } }
03 / OUTPUT<h1>Template lab</h1>
<footer>Nick</footer>
SOURCE + BINDINGS → RENDERER → CHECKED BYTES
Nift 4.12.0Native embedded renderer
Jinja2 3.1.6Python compiled templates
Nunjucks 3.2.4JavaScript template runtime
Handlebars 4.7.10Compiled presentation functions
LiquidJS 10.30.0Constrained template model
17,950measured samples375supported cells20timed scenarios750retained warmups

Fresh article: Nift 4.695 ms per invocation. Persistent 10,000-record render: Nift 34.085 ms, Handlebars 2.249 ms with preparation included. Low invocation cost does not establish sustained rendering throughput.

01 / the contract

The document comes first.

Independent data and expected bytes define the task. Participant templates express the same literal text, values, branches, named records and include expansions. No tracked builds, generated sites or application servers are measured.

Fresh process

Start → load → render

Runtime startup, modules, source/data loading, complete rendering and stdout capture. Milliseconds per invocation.

Persistent runtime

Prepare → render

Preloaded data and sources. Timed engine calls, batched where needed. Milliseconds per template operation.

Prepared templates

Render → render again

Parsed/compiled artifacts reused where public APIs permit. Nift source reuse still parses; it has no exposed prepared-AST handle.

The corpus is intentionally raw text. Automatic HTML escaping, contextual safety and untrusted-template sandboxing are not certified here. A separate special-character gate verifies that template-looking values remain data.

02 / operational latency

A fresh process has a price.

These totals include host-language startup, both frozen data variants, all scenario templates and complete intended output. A single render still preloads an unused second variant in every adapter. This is the reproducible harness boundary, not a hand-tuned minimal request or engine-only throughput.

Fresh end-to-end invocation
Fresh invocation median ms; 30–50 measured samples per cell. SVG · PNG. On narrow screens, scroll the chart and table horizontally.
Fresh invocation median ms; 30–50 measured samples per cell.
WorkloadNiftJinja2NunjucksHandlebarsLiquidJS
Literal4.42678.64250.70263.79763.970
Values4.32876.87851.88365.21363.657
Article4.69578.68654.57869.89369.959
1k records11.02480.40158.70469.804120.795

03 / preparation

Before the first render.

Jinja produces code, Nunjucks eager-compiles, Handlebars precompiles JavaScript source and LiquidJS parses tokens. These preparation artifacts differ. Nift exposes no standalone preparation API; its column is unavailable.

Persistent preparation only
Preparation median ms per template; 50 samples; logarithmic axis. SVG · PNG. On narrow screens, scroll the chart and table horizontally.
Preparation median ms per template; 50 samples; logarithmic axis.
WorkloadNiftJinja2NunjucksHandlebarsLiquidJS
Literal—0.2030.0180.0310.002
Values—0.7810.0840.2520.015
Article—1.8940.2690.7550.053

04 / records and output

More rows. More work.

Main source preparation plus rendering is timed on every operation. Nift uses its native render_text call. Preloaded contexts and output validation remain outside the timer.

Persistent source preparation + render
Median ms per render; 50 samples; logarithmic axis. SVG · PNG. On narrow screens, scroll the chart and table horizontally.
Median ms per render; 50 samples; logarithmic axis.
WorkloadNiftJinja2NunjucksHandlebarsLiquidJS
10 records0.0640.8890.1460.3810.191
100 records0.3641.0350.2450.3830.938
1,000 records3.2932.4941.5600.6498.677
10,000 records34.08516.88611.8202.24985.047

05 / prepared reuse

Preparation can be amortized.

These four engines reuse prepared templates with preloaded data. Nift is absent because it does not expose the same capability. Keeping a Nift Engine alive avoids process startup, but does not turn source reuse into parsed-template reuse.

Prepared-template rendering
Median ms per prepared render; 50 samples; logarithmic axis; Nift API unavailable. SVG · PNG. On narrow screens, scroll the chart and table horizontally.
Median ms per prepared render; 50 samples; logarithmic axis; Nift API unavailable.
WorkloadNiftJinja2NunjucksHandlebarsLiquidJS
10 records—0.0270.0120.0050.096
100 records—0.1720.1170.0210.836
1,000 records—1.5931.0380.2948.584
10,000 records—15.19410.2001.88484.503
Prepared template, alternating new data
Median total ms per repeated-render workload; 50 samples; logarithmic axis. SVG · PNG. On narrow screens, scroll the chart and table horizontally.
Median total ms per repeated-render workload; 50 samples; logarithmic axis.
WorkloadNiftJinja2NunjucksHandlebarsLiquidJS
100 renders—1.0280.0590.1760.775
1,000 renders—10.2980.6381.7037.691

06 / partials

Composition has two boundaries.

Memory-backed sources use normal warmed partial caches where available, while main preparation repeats. File-backed calls load from files with engine source/partial caches invalidated or disabled. OS caches stay warm. Nift includes its supported root-reset cost.

Memory-backed composition
Median ms per prepare + render; 50 samples. SVG · PNG. On narrow screens, scroll the chart and table horizontally.
Median ms per prepare + render; 50 samples.
WorkloadNiftJinja2NunjucksHandlebarsLiquidJS
Depth 10.0430.8000.1020.3170.097
Depth 40.0890.8140.1020.2670.086
Depth 80.1630.8220.1310.3750.157
File-backed composition
Median ms per file-backed prepare + render; 50 samples. SVG · PNG. On narrow screens, scroll the chart and table horizontally.
Median ms per file-backed prepare + render; 50 samples.
WorkloadNiftJinja2NunjucksHandlebarsLiquidJS
Depth 10.0781.3150.1870.4660.218
Depth 40.1682.7660.4030.9970.526
Depth 80.3004.7460.6221.6920.852

07 / realistic assembly

A page is more than interpolation.

The article combines metadata, navigation, sections, conditional output and a footer. Nested loops and a 2,000-record collection exercise lookup and output growth. Uppercase is the same ASCII transformation in every engine.

Persistent preparation + rendering
Median ms per render; 50 samples; logarithmic axis. SVG · PNG. On narrow screens, scroll the chart and table horizontally.
Median ms per render; 50 samples; logarithmic axis.
WorkloadNiftJinja2NunjucksHandlebarsLiquidJS
Article0.2752.0460.3730.9630.448
Nested loops1.0681.6000.5120.5992.073
2k collection7.1494.0422.6150.86717.205
Uppercase0.0210.4980.0360.1790.037

08 / source diversity

A thousand distinct templates.

Unique main sources carry distinct output suffixes. Every source is prepared and rendered; this is not a cache-hit claim. Values below are complete workload totals rather than amortized individual template times.

Prepare + render distinct templates
Median total ms per workload; 50 samples; logarithmic axis. SVG · PNG. On narrow screens, scroll the chart and table horizontally.
Median total ms per workload; 50 samples; logarithmic axis.
WorkloadNiftJinja2NunjucksHandlebarsLiquidJS
10 templates0.2124.0860.3081.1050.108
100 templates2.14239.9182.3806.2351.023
1,000 templates21.516392.40823.37264.67610.465

09 / resource scope

Memory belongs to a boundary.

These are unranked raw accounting observations, not memory-efficiency rankings. The final noop-child control rose from 16.75 to 80.75 MiB when its launch parent allocated 64 MiB: inherited wait4 floors can dominate fresh and whole-worker peaks. No constant is subtracted. Persistent-worker lifetime also includes preload, preparation, retained batch outputs and validation; it is not memory per render. Scopes remain separate.

Unranked fresh-child RSS accounting
Raw median maximum-child RSS MiB; inherited launch floor; unranked, 30–50 invocations per cell. SVG · PNG. On narrow screens, scroll the chart and table horizontally.
Raw median maximum-child RSS MiB; inherited launch floor; unranked, 30–50 invocations per cell.
WorkloadNiftJinja2NunjucksHandlebarsLiquidJS
Literal27.87527.87550.12552.63354.625
Article27.87527.87551.00053.14160.652
2k collection27.87527.87552.56253.90267.766
Persistent-worker high-water observations
Unranked whole-worker maximum RSS, MiB; launch floor and lifetime scope, not memory per render
WorkloadEngineOperationPeak MiB
literalNiftsource-reuse27.875
literalJinja2render27.875
literalNunjucksrender59.504
literalHandlebarsrender85.199
literalLiquidJSrender69.184
literalJinja2reuse27.875
literalNunjucksreuse71.754
literalHandlebarsreuse65.172
literalLiquidJSreuse68.129
literalJinja2parse27.875
literalNunjucksparse63.391
literalHandlebarsparse66.246
literalLiquidJSparse67.113
articleNiftsource-reuse27.875
articleJinja2render27.875
articleNunjucksrender73.113
articleHandlebarsrender81.598
articleLiquidJSrender82.656
articleJinja2reuse27.875
articleNunjucksreuse94.820
articleHandlebarsreuse94.762
articleLiquidJSreuse82.438
articleJinja2parse27.875
articleNunjucksparse63.020
articleHandlebarsparse67.078
articleLiquidJSparse69.355
collectionNiftsource-reuse27.875
collectionJinja2render27.875
collectionNunjucksrender94.496
collectionHandlebarsrender98.910
collectionLiquidJSrender103.289
collectionJinja2reuse27.875
collectionNunjucksreuse90.516
collectionHandlebarsreuse152.941
collectionLiquidJSreuse103.789
collectionJinja2parse27.875
collectionNunjucksparse63.297
collectionHandlebarsparse66.047
collectionLiquidJSparse70.125

10 / independent gates

A faster wrong document is rejected.

Cloud certification passed all 393 supported cells, including a separate raw-special-value fixture. Every timed render is compared against independent expected bytes. Fresh output hashes are retained; persistent workers check every batch output before emitting their timing row. Ordering, record counts, includes and changing-data variants follow the exact output contract.

The independent audit checks all 375 official cells, the complete sample index set, 17,950 measured observations, 750 separate warmups and every frozen corpus hash. No statistical outliers were removed. Thirty extra special-value/malformed/variant gates passed. Historical newline/Node-stdout preparation failures remain in the archived evidence; final certification and observations passed.

All measured medians, p95 and ranges
Fresh ms/invocation; all persistent modes ms/template operation; no boundary pooling
WorkloadEngineModeMedianp95MinMaxSamples
literalNiftfresh4.42615.62123.64649.066350
literalNiftsource-reuse0.01520.02860.01460.029850
literalJinja2fresh78.641985.056373.3372100.944150
literalJinja2render0.23900.32550.21630.403950
literalJinja2reuse0.00900.01600.00870.019850
literalJinja2parse0.20330.38970.18770.999550
literalNunjucksfresh50.702260.130147.493661.788350
literalNunjucksrender0.02270.10420.01400.127450
literalNunjucksreuse0.00050.00150.00040.001750
literalNunjucksparse0.01830.07980.01090.126350
literalHandlebarsfresh63.797072.547960.217177.948950
literalHandlebarsrender0.04370.20810.01890.286050
literalHandlebarsreuse0.00140.00840.00130.011650
literalHandlebarsparse0.03130.10950.01150.174450
literalLiquidJSfresh63.970277.252360.775680.527150
literalLiquidJSrender0.00360.02190.00220.026550
literalLiquidJSreuse0.00100.01180.00090.025250
literalLiquidJSparse0.00160.00580.00130.021250
interpolationNiftfresh4.32765.69803.64968.949450
interpolationNiftsource-reuse0.02800.04360.02710.054550
interpolationJinja2fresh76.878186.774773.880794.083150
interpolationJinja2render0.67661.07040.63231.355050
interpolationJinja2reuse0.01200.02410.01170.048050
interpolationJinja2parse0.78081.71270.60732.440550
interpolationNunjucksfresh51.882958.747649.117762.128550
interpolationNunjucksrender0.07120.17920.04760.303550
interpolationNunjucksreuse0.00070.00300.00060.009050
interpolationNunjucksparse0.08440.24070.04700.296450
interpolationHandlebarsfresh65.213278.236262.079181.665750
interpolationHandlebarsrender0.26920.59140.13790.707750
interpolationHandlebarsreuse0.00330.02470.00160.028850
interpolationHandlebarsparse0.25190.69890.13691.423050
interpolationLiquidJSfresh63.657471.234460.940786.430050
interpolationLiquidJSrender0.03720.16180.02420.235150
interpolationLiquidJSreuse0.01380.06130.01100.095250
interpolationLiquidJSparse0.01530.09460.01050.107850
conditionNiftfresh4.18924.81433.70125.313650
conditionNiftsource-reuse0.02290.03900.02130.051550
conditionJinja2fresh77.844488.065873.050490.972650
conditionJinja2render0.53210.76210.49451.067750
conditionJinja2reuse0.00980.01690.00940.026350
conditionJinja2parse0.48010.83120.46041.193450
conditionNunjucksfresh51.050356.430247.972358.093650
conditionNunjucksrender0.05690.19900.03710.549550
conditionNunjucksreuse0.00050.00190.00040.004250
conditionNunjucksparse0.04670.20820.03710.314550
conditionHandlebarsfresh66.108172.536562.652175.746650
conditionHandlebarsrender0.32290.74970.14891.083250
conditionHandlebarsreuse0.00240.01510.00160.033850
conditionHandlebarsparse0.20600.52960.12730.651050
conditionLiquidJSfresh63.980769.898961.773974.156750
conditionLiquidJSrender0.03970.15540.02030.268550
conditionLiquidJSreuse0.00950.04740.00470.070150
conditionLiquidJSparse0.00990.07220.00720.080250
nested-objectNiftfresh4.18754.79463.66768.539550
nested-objectNiftsource-reuse0.02290.03300.02210.034050
nested-objectJinja2fresh76.995383.199472.808188.004550
nested-objectJinja2render0.55820.63470.52610.744950
nested-objectJinja2reuse0.01130.02180.01070.029350
nested-objectJinja2parse0.49890.78860.47602.107750
nested-objectNunjucksfresh51.195058.146947.761063.591750
nested-objectNunjucksrender0.05240.21490.03860.538950
nested-objectNunjucksreuse0.00060.00940.00050.016450
nested-objectNunjucksparse0.04420.25680.03500.304250
nested-objectHandlebarsfresh65.136378.203361.749381.062850
nested-objectHandlebarsrender0.19320.54830.10820.718850
nested-objectHandlebarsreuse0.00190.00640.00140.017150
nested-objectHandlebarsparse0.15860.40760.09481.038550
nested-objectLiquidJSfresh63.987468.424160.325372.157550
nested-objectLiquidJSrender0.04450.15890.01880.179150
nested-objectLiquidJSreuse0.01080.03510.00770.067450
nested-objectLiquidJSparse0.00980.08620.00650.164550
loop-10Niftfresh4.40656.06603.76977.807950
loop-10Niftsource-reuse0.06370.13210.06060.202650
loop-10Jinja2fresh77.4983105.250773.9972116.952750
loop-10Jinja2render0.88881.05650.84211.310550
loop-10Jinja2reuse0.02650.04750.02590.057950
loop-10Jinja2parse0.81601.78050.78412.504450
loop-10Nunjucksfresh52.694860.509550.747167.617050
loop-10Nunjucksrender0.14610.38230.08500.614050
loop-10Nunjucksreuse0.01170.02100.01020.026450
loop-10Nunjucksparse0.10180.35030.07750.518950
loop-10Handlebarsfresh67.328884.606863.8084108.482450
loop-10Handlebarsrender0.38090.99080.19691.281650
loop-10Handlebarsreuse0.00510.03130.00290.091050
loop-10Handlebarsparse0.27280.70890.18370.914650
loop-10LiquidJSfresh65.734384.358763.127190.148250
loop-10LiquidJSrender0.19070.74120.11231.046850
loop-10LiquidJSreuse0.09650.19750.08680.506850
loop-10LiquidJSparse0.01640.11650.01280.164950
loop-100Niftfresh4.83965.35694.33075.828350
loop-100Niftsource-reuse0.36430.66320.35431.155950
loop-100Jinja2fresh77.147684.237773.324491.355950
loop-100Jinja2render1.03481.16850.99271.426750
loop-100Jinja2reuse0.17180.20410.16690.385850
loop-100Jinja2parse0.82951.76970.78592.329350
loop-100Nunjucksfresh53.609758.603751.162162.737250
loop-100Nunjucksrender0.24490.92130.18291.252050
loop-100Nunjucksreuse0.11680.17950.09850.354050
loop-100Nunjucksparse0.11500.36360.08170.453450
loop-100Handlebarsfresh66.947472.466564.468586.973750
loop-100Handlebarsrender0.38340.93950.22411.555350
loop-100Handlebarsreuse0.02110.06890.01400.263450
loop-100Handlebarsparse0.29490.78530.18231.116950
loop-100LiquidJSfresh74.483382.804369.979085.546550
loop-100LiquidJSrender0.93771.94410.82372.888250
loop-100LiquidJSreuse0.83631.24280.77642.238250
loop-100LiquidJSparse0.01750.13520.01300.208250
loop-1000Niftfresh11.024312.432110.555013.808230
loop-1000Niftsource-reuse3.29343.65503.21927.224250
loop-1000Jinja2fresh80.400689.942076.521394.688830
loop-1000Jinja2render2.49412.91822.41193.128950
loop-1000Jinja2reuse1.59272.73831.54173.082650
loop-1000Jinja2parse0.81041.67550.77281.854450
loop-1000Nunjucksfresh58.704364.943055.672970.458330
loop-1000Nunjucksrender1.56022.88251.12714.774550
loop-1000Nunjucksreuse1.03811.88360.95052.439750
loop-1000Nunjucksparse0.09800.45650.07810.483950
loop-1000Handlebarsfresh69.803676.803666.962178.988730
loop-1000Handlebarsrender0.64931.49980.37173.581950
loop-1000Handlebarsreuse0.29370.56940.12930.939050
loop-1000Handlebarsparse0.31771.83610.20861.961850
loop-1000LiquidJSfresh120.7950133.3768116.0802138.000730
loop-1000LiquidJSrender8.676914.37647.718716.632350
loop-1000LiquidJSreuse8.583916.42517.740025.917750
loop-1000LiquidJSparse0.01780.12600.01300.153250
loop-10000Niftfresh76.750384.052871.437584.697330
loop-10000Niftsource-reuse34.084737.829733.200169.589450
loop-10000Jinja2fresh113.5029122.7730106.7649124.648430
loop-10000Jinja2render16.885818.721016.292221.887350
loop-10000Jinja2reuse15.194316.084315.044224.668750
loop-10000Jinja2parse0.82171.82270.78833.001250
loop-10000Nunjucksfresh98.8274109.090993.4323115.384130
loop-10000Nunjucksrender11.819517.720010.007027.011150
loop-10000Nunjucksreuse10.200013.77709.171721.615050
loop-10000Nunjucksparse0.11240.36680.07380.539750
loop-10000Handlebarsfresh99.3733109.861693.0798112.213230
loop-10000Handlebarsrender2.24865.31662.10868.411350
loop-10000Handlebarsreuse1.88374.22441.69537.154750
loop-10000Handlebarsparse0.25780.79670.18370.949050
loop-10000LiquidJSfresh240.1026260.8873227.0205262.981730
loop-10000LiquidJSrender85.046797.784981.6179110.659850
loop-10000LiquidJSreuse84.503097.567281.7115103.008750
loop-10000LiquidJSparse0.02020.16740.01410.196350
nested-loopsNiftfresh6.09097.14615.46707.929250
nested-loopsNiftsource-reuse1.06761.70101.03762.920650
nested-loopsJinja2fresh77.226185.127573.922895.461450
nested-loopsJinja2render1.60021.75901.54892.358950
nested-loopsJinja2reuse0.34470.43430.33640.741850
nested-loopsJinja2parse1.20871.99131.15552.385950
nested-loopsNunjucksfresh53.607655.879151.314962.615150
nested-loopsNunjucksrender0.51151.38990.34482.359450
nested-loopsNunjucksreuse0.24790.33730.20610.394150
nested-loopsNunjucksparse0.17690.65210.12621.292950
nested-loopsHandlebarsfresh67.713673.272764.808174.244250
nested-loopsHandlebarsrender0.59881.62300.33113.351250
nested-loopsHandlebarsreuse0.05830.11590.03740.257150
nested-loopsHandlebarsparse0.41710.96230.27921.772950
nested-loopsLiquidJSfresh78.505287.421775.191590.632150
nested-loopsLiquidJSrender2.07263.50771.78074.177150
nested-loopsLiquidJSreuse1.86782.82901.68375.083150
nested-loopsLiquidJSparse0.02690.15720.02120.200550
includes-1Niftfresh4.39874.75693.73885.498650
includes-1Niftsource-reuse0.04340.08260.04110.093450
includes-1Niftfiles0.07810.11730.07580.123350
includes-1Jinja2fresh77.141686.747774.2007100.481650
includes-1Jinja2render0.79991.17830.75591.503250
includes-1Jinja2reuse0.01640.03500.01610.051350
includes-1Jinja2parse0.73471.37110.69351.490450
includes-1Jinja2files1.31531.53851.25181.650650
includes-1Nunjucksfresh52.859263.261051.047471.126150
includes-1Nunjucksrender0.10190.35460.06100.580550
includes-1Nunjucksreuse0.00210.03270.00190.040550
includes-1Nunjucksparse0.07670.36100.05760.622150
includes-1Nunjucksfiles0.18710.53830.12140.882950
includes-1Handlebarsfresh66.796271.712564.037477.032750
includes-1Handlebarsrender0.31700.83590.15781.044150
includes-1Handlebarsreuse0.00300.02070.00180.046650
includes-1Handlebarsparse0.23410.56150.14760.892350
includes-1Handlebarsfiles0.46611.09530.27551.499350
includes-1LiquidJSfresh65.203573.148162.893576.932950
includes-1LiquidJSrender0.09740.35220.04160.419850
includes-1LiquidJSreuse0.02450.07460.01810.152150
includes-1LiquidJSparse0.01550.08620.01140.118650
includes-1LiquidJSfiles0.21840.59160.13160.822450
includes-4Niftfresh4.43925.16733.81265.393250
includes-4Niftsource-reuse0.08900.18900.08570.300550
includes-4Niftfiles0.16780.23770.16160.246750
includes-4Jinja2fresh78.432785.473474.458188.980750
includes-4Jinja2render0.81391.01790.77341.063750
includes-4Jinja2reuse0.03070.05020.02970.084550
includes-4Jinja2parse0.89881.83810.69712.996050
includes-4Jinja2files2.76603.26772.64204.376050
includes-4Nunjucksfresh54.156963.153351.983867.199250
includes-4Nunjucksrender0.10190.48340.06690.650350
includes-4Nunjucksreuse0.00880.04010.00620.074850
includes-4Nunjucksparse0.11140.35720.06520.445650
includes-4Nunjucksfiles0.40341.13820.22501.680850
includes-4Handlebarsfresh67.779175.585064.656580.950650
includes-4Handlebarsrender0.26710.82090.15481.069950
includes-4Handlebarsreuse0.00370.03310.00240.039150
includes-4Handlebarsparse0.28071.01620.16671.508350
includes-4Handlebarsfiles0.99692.36950.49962.602750
includes-4LiquidJSfresh65.484474.783063.106378.759050
includes-4LiquidJSrender0.08590.35750.04510.502350
includes-4LiquidJSreuse0.03210.13460.02460.140850
includes-4LiquidJSparse0.01890.08520.01220.137250
includes-4LiquidJSfiles0.52561.46850.30301.621650
includes-8Niftfresh4.87415.55604.18117.328850
includes-8Niftsource-reuse0.16290.23820.15800.277650
includes-8Niftfiles0.30040.46620.28820.621850
includes-8Jinja2fresh83.435996.154278.0738108.732750
includes-8Jinja2render0.82161.10680.77991.326050
includes-8Jinja2reuse0.04880.08540.04690.138350
includes-8Jinja2parse0.75051.78820.69812.168850
includes-8Jinja2files4.74585.56284.51857.940850
includes-8Nunjucksfresh58.112262.526354.242966.178450
includes-8Nunjucksrender0.13150.53040.08001.103350
includes-8Nunjucksreuse0.01980.08360.01360.111750
includes-8Nunjucksparse0.09470.29770.05970.529250
includes-8Nunjucksfiles0.62241.60660.38183.418750
includes-8Handlebarsfresh74.641582.725868.839785.290350
includes-8Handlebarsrender0.37540.73090.15751.770150
includes-8Handlebarsreuse0.00510.01760.00330.020750
includes-8Handlebarsparse0.25460.91410.14551.070450
includes-8Handlebarsfiles1.69243.85040.79834.952450
includes-8LiquidJSfresh68.381978.843364.125988.497750
includes-8LiquidJSrender0.15690.39230.06320.577050
includes-8LiquidJSreuse0.05050.17600.04030.185550
includes-8LiquidJSparse0.01620.09270.01120.125350
includes-8LiquidJSfiles0.85242.90290.55713.549250
articleNiftfresh4.69495.50394.04565.872550
articleNiftsource-reuse0.27480.53070.26060.729750
articleJinja2fresh78.685587.715175.141490.629250
articleJinja2render2.04643.20861.92443.943250
articleJinja2reuse0.04560.06010.04180.194850
articleJinja2parse1.89443.50911.79723.762950
articleNunjucksfresh54.578160.541951.630871.669650
articleNunjucksrender0.37301.31400.22121.677350
articleNunjucksreuse0.02190.04720.01880.076050
articleNunjucksparse0.26851.07630.19491.568750
articleHandlebarsfresh69.892877.100867.3761110.063450
articleHandlebarsrender0.96272.30160.51744.298050
articleHandlebarsreuse0.00780.03440.00520.077850
articleHandlebarsparse0.75491.55340.47032.484450
articleLiquidJSfresh69.959579.929866.882285.377050
articleLiquidJSrender0.44841.00920.22252.858350
articleLiquidJSreuse0.20910.48500.16180.778650
articleLiquidJSparse0.05310.35700.04000.792250
collectionNiftfresh17.644024.597816.877226.737530
collectionNiftsource-reuse7.148712.00386.909613.075850
collectionJinja2fresh84.339791.846879.677593.369230
collectionJinja2render4.04204.91963.94278.242950
collectionJinja2reuse3.12403.44873.07247.068850
collectionJinja2parse0.77361.21530.72681.746550
collectionNunjucksfresh63.187470.935760.017873.273330
collectionNunjucksrender2.61484.46712.06315.043550
collectionNunjucksreuse2.09182.92631.87753.035350
collectionNunjucksparse0.10240.38020.07210.649850
collectionHandlebarsfresh72.274984.265968.339584.820530
collectionHandlebarsrender0.86732.62720.52973.304850
collectionHandlebarsreuse0.74861.21620.44992.348550
collectionHandlebarsparse0.25481.05480.18591.253350
collectionLiquidJSfresh151.2657164.8805142.5834167.668430
collectionLiquidJSrender17.204829.618215.746833.403150
collectionLiquidJSreuse17.445131.508115.545635.701550
collectionLiquidJSparse0.01660.12730.01300.156950
many-renders-100Niftfresh6.24416.76015.82108.463130
many-renders-100Niftsource-reuse0.02180.02820.02120.043550
many-renders-100Jinja2fresh126.7340141.3064121.0456142.564130
many-renders-100Jinja2render0.48730.53610.46260.561650
many-renders-100Jinja2reuse0.01030.01790.01000.030750
many-renders-100Jinja2parse0.45510.52070.42520.650150
many-renders-100Nunjucksfresh88.381694.861982.444895.222730
many-renders-100Nunjucksrender0.02620.12690.02400.218050
many-renders-100Nunjucksreuse0.00060.00130.00040.002150
many-renders-100Nunjucksparse0.02440.13100.02290.226750
many-renders-100Handlebarsfresh135.3628147.9425121.7949149.678930
many-renders-100Handlebarsrender0.10000.27420.08690.353350
many-renders-100Handlebarsreuse0.00180.00390.00140.005150
many-renders-100Handlebarsparse0.07360.23090.06600.254550
many-renders-100LiquidJSfresh79.200089.719874.4932110.183730
many-renders-100LiquidJSrender0.01610.04470.01480.124250
many-renders-100LiquidJSreuse0.00770.01760.00700.030650
many-renders-100LiquidJSparse0.00660.01730.00630.040350
many-renders-1000Niftfresh26.772329.773325.704640.892030
many-renders-1000Niftsource-reuse0.02250.03150.02160.051350
many-renders-1000Jinja2fresh556.2439593.8707532.9274599.169530
many-renders-1000Jinja2render0.47410.50200.45520.505650
many-renders-1000Jinja2reuse0.01030.01500.01000.017050
many-renders-1000Jinja2parse0.44300.47480.42030.587450
many-renders-1000Nunjucksfresh264.5821299.5823253.6532355.859430
many-renders-1000Nunjucksrender0.02490.06110.02280.100250
many-renders-1000Nunjucksreuse0.00060.00080.00040.001050
many-renders-1000Nunjucksparse0.02300.03950.02180.102150
many-renders-1000Handlebarsfresh318.1022348.4469304.2679439.489130
many-renders-1000Handlebarsrender0.08420.11110.07470.186350
many-renders-1000Handlebarsreuse0.00170.00320.00160.004750
many-renders-1000Handlebarsparse0.06930.09080.06510.122950
many-renders-1000LiquidJSfresh172.7177192.2219164.9564271.721330
many-renders-1000LiquidJSrender0.01510.02530.01300.064650
many-renders-1000LiquidJSreuse0.00770.01230.00690.015350
many-renders-1000LiquidJSparse0.00590.00890.00570.014150
many-templates-10Niftfresh4.73715.10564.14905.138430
many-templates-10Niftsource-reuse0.02120.04320.02060.049150
many-templates-10Jinja2fresh80.827286.576877.3650100.463130
many-templates-10Jinja2render0.40860.47690.38070.580250
many-templates-10Jinja2reuse0.00950.00990.00930.025450
many-templates-10Jinja2parse0.38050.48120.35580.846850
many-templates-10Nunjucksfresh54.638361.591652.239761.749930
many-templates-10Nunjucksrender0.03080.15230.02030.171350
many-templates-10Nunjucksreuse0.00050.00180.00040.005350
many-templates-10Nunjucksparse0.02400.09400.01940.189550
many-templates-10Handlebarsfresh70.546680.049767.315882.001730
many-templates-10Handlebarsrender0.11050.29870.05000.394550
many-templates-10Handlebarsreuse0.00170.00350.00130.004350
many-templates-10Handlebarsparse0.07720.27540.05220.350250
many-templates-10LiquidJSfresh66.375470.334463.056370.991730
many-templates-10LiquidJSrender0.01080.06200.00890.092350
many-templates-10LiquidJSreuse0.00500.01510.00410.021650
many-templates-10LiquidJSparse0.00460.01630.00440.020750
many-templates-100Niftfresh7.44208.05546.86698.149430
many-templates-100Niftsource-reuse0.02140.02350.02090.037250
many-templates-100Jinja2fresh120.9770125.9972113.7080136.991130
many-templates-100Jinja2render0.39920.43290.37760.450750
many-templates-100Jinja2reuse0.00970.00990.00940.019350
many-templates-100Jinja2parse0.36530.42830.34390.495950
many-templates-100Nunjucksfresh87.322291.384184.488393.933030
many-templates-100Nunjucksrender0.02380.10780.02130.188750
many-templates-100Nunjucksreuse0.00070.00140.00060.002450
many-templates-100Nunjucksparse0.02160.12140.01970.217550
many-templates-100Handlebarsfresh132.5488142.7682127.4625143.931630
many-templates-100Handlebarsrender0.06230.19670.04960.333150
many-templates-100Handlebarsreuse0.00200.00320.00150.006750
many-templates-100Handlebarsparse0.05790.16730.04720.251250
many-templates-100LiquidJSfresh82.736190.853178.609393.343130
many-templates-100LiquidJSrender0.01020.06140.00890.099750
many-templates-100LiquidJSreuse0.00480.01000.00430.028450
many-templates-100LiquidJSparse0.00480.02070.00450.026050
many-templates-1000Niftfresh35.825838.363334.016258.669830
many-templates-1000Niftsource-reuse0.02150.02510.02110.036950
many-templates-1000Jinja2fresh498.1425570.2601482.9707593.352930
many-templates-1000Jinja2render0.39240.46240.37370.487450
many-templates-1000Jinja2reuse0.01030.01660.00980.017450
many-templates-1000Jinja2parse0.35960.38570.34470.393850
many-templates-1000Nunjucksfresh341.0884378.6479328.4072447.405730
many-templates-1000Nunjucksrender0.02340.06790.02060.110150
many-templates-1000Nunjucksreuse0.00090.00170.00080.002150
many-templates-1000Nunjucksparse0.02060.04760.01940.118150
many-templates-1000Handlebarsfresh371.0627407.8127355.6176407.945230
many-templates-1000Handlebarsrender0.06470.13680.05650.154850
many-templates-1000Handlebarsreuse0.00390.00880.00220.010050
many-templates-1000Handlebarsparse0.04990.08060.04730.113450
many-templates-1000LiquidJSfresh163.7064174.3214151.3854234.337230
many-templates-1000LiquidJSrender0.01050.01740.00930.018750
many-templates-1000LiquidJSreuse0.00540.01060.00480.012050
many-templates-1000LiquidJSparse0.00450.00710.00430.010850
transformNiftfresh3.98724.78673.56695.150350
transformNiftsource-reuse0.02110.03620.02060.046850
transformJinja2fresh76.718486.989773.241994.550350
transformJinja2render0.49800.72470.47291.098850
transformJinja2reuse0.01000.01970.00960.021750
transformJinja2parse0.48121.05870.45771.408450
transformNunjucksfresh50.404857.168048.728258.683350
transformNunjucksrender0.03570.20930.02540.213350
transformNunjucksreuse0.00060.00170.00050.003550
transformNunjucksparse0.03300.18250.02110.273850
transformHandlebarsfresh64.823473.400462.051279.870350
transformHandlebarsrender0.17890.42240.09150.436250
transformHandlebarsreuse0.00220.01180.00160.037950
transformHandlebarsparse0.13980.40500.09390.571150
transformLiquidJSfresh63.541868.237461.364979.612050
transformLiquidJSrender0.03700.15810.02700.203450
transformLiquidJSreuse0.00900.04900.00460.065550
transformLiquidJSparse0.01280.07190.00570.092250

11 / practitioner view

Would I actually use Nift as a template engine?

Qualitative practitioner assessment / not benchmark evidence

Human + agent: Nift for Nift-owned composition, Jinja2 for an existing Python application, Handlebars for logic-light JS prepared reuse. Agent-primary: the same direct conditional choices; named bindings, source identity and output contracts help automated maintenance, but they do not erase the large source-render gap or missing prepared API. Nift is an attractive text-template language in its own right. Its value expressions, named loop locals and explicit includes make realistic composition inspectable. These are language advantages, independent of the website generator around it.

The API matters as much as syntax.

Nift’s source-versus-path distinction and per-render Context separate data, source policy and execution cleanly. Jinja/Nunjucks remain familiar and expressive in their existing hosts. Handlebars and Liquid deliberately restrict logic; that can make a presentation layer easier to maintain, rather than weaker.

The implementation exposed concrete conventions: Jinja’s dot lookup collided with a dictionary key named items, and its default newline policy changed bytes. Handlebars compile is lazy, so prepared functions must be forced before a reuse timer. Exact fixtures caught these differences. Nift source caching also needed explicit filesystem treatment.

What would I want an agent to maintain?

Named bindings, predictable scopes, explicit composition and a declared output/escaping contract matter more than minimum character count. Nift’s richer functions can remove awkward helper plumbing, but business policy and side effects should not drift into templates accidentally. Formatted Nift, Jinja and Nunjucks are all good representations; constrained Handlebars/Liquid can be preferable when the project wants a smaller editing surface.

Current preferences at equal performance: requirements, not a universal ranking
RequirementPreferenceReason
Small native text generationNift is a credible first choiceDirect embedded renderer; named scopes, expressive text syntax, explicit source/path APIs.
Existing Python applicationJinja2Native Python values and concrete framework integration already in the application.
Expressive JS application viewsNunjucksNative JS data and view composition without a native library deployment dependency.
Logic-light JS views with heavy reuseHandlebarsCompiled functions and application-owned helpers match the desired presentation boundary.
Product standardized on Liquid syntaxLiquidJSIts constrained filters/blocks are the required authoring contract.
Nift-owned or mixed-generation projectNiftShared expression/composition model plus tracked project ownership.
Agent-primary Nift-owned compositionNiftExplicit scopes/includes and checked output contract within the existing project; standalone prepared workloads remain a host-engine choice.
Repeated fixed complex server templates todayA prepared-template engineA concrete public preparation/reuse capability Nift does not yet expose.

Present-day versus mature Nift.

A public prepared-template artifact is the major standalone gap. I want explicit source identity, include invalidation, lifetime and concurrency contracts—not an undocumented benchmark fast path. If those become reliable and repeated-render performance is comparable, I see no architectural requirement to retain another renderer underneath Nift.

Existing Python/JS projects may still choose their host engine because of concrete value/framework/deployment requirements. Nift-owned projects already have a compelling single-model advantage. AI-DX authoring safety is qualitative: autonomous edit success, partial-error recovery and product-native structured feedback were not measured. Harness JSON is not a product feature. Context-sensitive HTML escaping, sandboxing, async filters, localization and streaming were not certified by this text-rendering campaign.

Full practitioner review ↗

12 / frozen evidence

Every number has a source.

One fresh g6-standard-4 shared-CPU Linode, us-east, Ubuntu 24.04. AMD EPYC 7642 host CPU, 4 shared vCPUs / 8 GiB RAM, Linux 6.8.0-134-generic, Python 3.12.3 and Node 22.22.1. All participants use one CPU affinity; order rotates within each round. Two separate warmup rounds, workload-sensitive fresh counts and 50 persistent samples. Batches are frozen from local feasibility. There is no machine-cold cache claim.

Nift source: c14d06835bca515a5281e41da0e40219c2d60ef0
Measured suite: 3c0dcdd1aad3cbb0a0c638c9041233b1e329dc6f
Canonical evidence: 19e390183b9bcb039abe6aa553ad88a2305b49ee
Experiment assessment/audit: 3c0dcdd1aad3cbb0a0c638c9041233b1e329dc6f

Raw observations, warmups, environment, hashes and audit ↗ · Adapter boundaries ↗ · Protocol ↗

Publication contains compact summary statistics and these displayed figures. Raw samples, corpora, traces and lifecycle receipts remain in the evidence repository. Existing reports and graph designs are preserved.