Template language
Runjucks aims to match Nunjucks templating closely. This page summarizes user-visible behavior. For exact Node entrypoints, see JavaScript API.
Text and comments
Section titled “Text and comments”| Feature | Notes |
|---|---|
| Plain text | Output as-is. |
{# … #} | Comments removed from output. |
{{ … }} expressions
Section titled “{{ … }} expressions”- Literals — strings, numbers, booleans,
null. - Variables — dotted and bracket paths;
inand chained comparisons. - Operators — arithmetic, logic,
not, comparisons. - Aggregates —
[ … ]lists and{ … }objects. - Inline conditionals —
a if cond else b. - Filters —
value \| filterandvalue \| filter(args); pipelines chain left-to-right. istests —value is nameand call forms such asequalto(…)/sameas(…)where supported.- Calls — macros,
super(),caller(), and built-in globals such asrange,cycler,joiner(see JavaScript API for globals and custom behavior).
Slices: Jinja-style array slices (e.g. arr[1:4], arr[::2]) are accepted without a separate “compat” install — unlike stock nunjucks, which needs installJinjaCompat() for that syntax.
Built-in filter names and behavior are listed in the Node.js API reference (TypeDoc). The set is large and growing; if something differs from Nunjucks, check Limitations.
{% … %} tags
Section titled “{% … %} tags”Supported constructs include:
if/elif/else/endif— includingelseifalias.for/else/endfor— single or multiple loop variables, tuple unpack,key, valueover objects (stable key order),loop.*(index,index0,first,last,length,revindex,revindex0), optional{% else %}when the sequence is empty.switch/case/default/endswitch— including fall-through behavior for emptycasebodies (JavaScript-style).set—{% set x = expr %}, multi-target{% set a, b = expr %}, and block capture{% set x %}…{% endset %}with frame rules aligned to Nunjucks.include— expression template name;ignore missing; optionalwithout context/with context(see Limitations for nuances vs upstream).extends,block/endblock,{{ super() }}— multi-level inheritance.macro/endmacro— defaults and keyword arguments at call sites.import/from— namespaces and imported macros (top-level macros from imported templates).call/endcall,caller()— optional caller argument lists on the opening{% call %}tag.filter/endfilter— block filtered as a whole.raw/endraw,verbatim/endverbatim— literal regions; nesting is balanced like Nunjucks.
Async tags
Section titled “Async tags”The following tags are supported inside async render (renderStringAsync / renderTemplateAsync). Using them with the synchronous renderString raises an error directing you to the async API.
asyncEach/endeach— sequential iteration, same behavior asforbut signals async intent.{% asyncEach item in items %}{{ item }}{% endeach %}.asyncAll/endall— parallel-intent iteration (currently sequential in Runjucks, matching Nunjucks behavior).{% asyncAll item in items %}{{ item }}{% endall %}.ifAsync/endif— conditional that may depend on async-resolved values.{% ifAsync show %}visible{% endif %}.
Whitespace control
Section titled “Whitespace control”Nunjucks-style trim markers work: {%-, -%}, {{-, -}}, and the interaction of trimBlocks / lstripBlocks with the lexer (configured on the environment — see JavaScript API). Block-tag trimming does not apply the same rules to comment-only lines as to {% %} tags; endraw / endverbatim closing tags follow upstream newline behavior.
Custom tag extensions
Section titled “Custom tag extensions”Register opening tag names (and optional closing names) on the environment; your process(context, args, body) runs when those tags appear. This is a declarative model — not the Nunjucks extension API that customizes parsing in JavaScript. See JavaScript API.
When in doubt
Section titled “When in doubt”Use the Nunjucks templating docs for language concepts, then verify against Runjucks behavior or the Limitations page. A detailed parity backlog for maintainers lives in the GitHub repo (NUNJUCKS_PARITY.md).