Skip to content

Coming from Handlebars, Mustache, or Liquid

kBars deliberately mixes syntax from all three engines — Mustache's tag shape, Handlebars' block helpers and ..//@index vocabulary, Liquid's | filter pipeline — rather than inventing its own. If you already know one of them, most of kBars is recognizable on sight. This page is a fast map from what you already know to what kBars calls it, so you can skip re-deriving the syntax from scratch.

It is not a migration tool: kBars does not execute Handlebars, Mustache, or Liquid templates unmodified, and porting real templates still means checking the pages linked throughout this table against your source engine's docs.

What carries over

Syntax Where you've seen it In kBars
{{ name }} Mustache, Handlebars Identical — escaped interpolation. See Interpolation.
{{{ name }}} Mustache, Handlebars Identical — unescaped interpolation. Liquid has no triple-brace form; its filters are the closest equivalent to opting out of escaping (see below).
{{! comment }} Mustache, Handlebars Identical shape and meaning — produces no output.
{{#if x}}…{{else if y}}…{{else}}…{{/if}} Handlebars Identical, including the else if chain. See Blocks.
{{#each items}}…{{else}}…{{/each}} Handlebars Identical name and {{else}}-on-empty behavior. See Blocks.
{{#with obj}}…{{/with}} Handlebars Identical — pushes obj as the new context for the body.
../foo, ../../foo Handlebars Identical — walks up the context stack one frame per ../. See Interpolation.
@index / @key Handlebars Identical names and meaning inside {{#each}}.
{{> key }} Mustache, Handlebars Same tag; how key resolves to a template is configured by whoever builds the application, not baked into the template source. See Partials.
{{{{raw}}}}…{{{{/raw}}}} Handlebars Identical four-brace raw block.
~ whitespace trimming ({{~ x }}, {{ x ~}}) Handlebars Identical marker and placement rules. See Template Basics.
Standalone-line whitespace stripping (a tag alone on its line has the line's surrounding whitespace removed, even with no ~) Mustache Identical rule, layered underneath the ~ markers above.
\{{ literal }} Handlebars Identical — a backslash before {{ escapes it to literal text.
\| filter/transform pipeline ({{ name \| upcase }}) Liquid Same pipe syntax and left-to-right chaining. See Transforms. Handlebars has no pipe operator at all — see below.
{{#*inline "name"}}…{{/inline}} inline partials Handlebars Same block-scoped definition-then-invoke behavior, but the name is an unquoted identifier and there is no * — kBars spells it {{#inline name}}…{{/inline}}. See Partials.
{{#> partial}}…{{/partial}} partial blocks Handlebars Only the failover half: a resolution miss renders the block body as fallback content, same as Handlebars. kBars spells the close {{/>}} (bare) or {{/> partial}} (named, must match the open key) rather than reusing the block name; there is no {{> @partial-block }} re-entry. See Partials.

What's renamed

Handlebars / Mustache / Liquid kBars Difference beyond the name
Liquid filters ({{ x \| upcase }}) Transforms Same pipe syntax; kBars's catalog (46 built-ins across strings/math/lists/date-times) is its own, not Liquid's — check the transform family pages rather than assuming a Liquid filter name and behavior carry over unchanged.
Handlebars helpers ({{formatDate date "YYYY"}}, prefix-call syntax) Transforms, but postfix-pipe only There is no prefix-call syntax in kBars — everything a helper would do goes through \| name: arg instead. A custom transform is registered by whoever builds the application you're writing templates for.
Mustache inverted section ({{^x}}…{{/x}}) {{#unless x}}…{{else}}…{{/unless}} Same "renders when falsy" meaning, spelled as a distinct block tag (Handlebars-style) instead of Mustache's ^ sigil on a section.
Mustache section ({{#x}}…{{/x}}, overloaded for both truthy-conditional and list iteration and context-push) {{#if x}}, {{#each x}}, {{#with x}} kBars splits Mustache's one overloaded tag into three explicit ones (Handlebars' approach) — a struct value under {{#x}} in Mustache implicitly pushes context the way {{#with}} does in kBars; a list implicitly iterates the way {{#each}} does.
Liquid {% for item in list %} {{#each list}} kBars has no in clause or loop variable name — the loop body reads the current element via this/an identifier, and the element itself becomes the pushed context (Handlebars' model), not a named loop variable (Liquid's model).
Liquid forloop.index (1-based), forloop.index0, forloop.first, forloop.last @index (0-based) kBars has no @first/@last — test @index == 0 (or use a \| size comparison) instead.
Liquid {% assign x = … %}, {% capture x %}…{% endcapture %} {{= @env/x = … }}, {{= @local/x = … }} kBars has no bare/global assignment target — every binding is namespaced to @env (render-global, survives block boundaries) or @local (frame-scoped, dropped when its block ends). See Scoped Variables.
Liquid {% include 'name' %} / {% render 'name' %} {{> key }} kBars partials take at most one context argument ({{> key ctx }}), not Liquid's named-parameter list ({% render 'name', foo: bar %}).
Liquid {% raw %}…{% endraw %} {{{{raw}}}}…{{{{/raw}}}} Same purpose, Handlebars' four-brace spelling instead of Liquid's tag.
Liquid {%- x -%} / {{- x -}} hyphen trimming {{~ x ~}} tilde trimming Same idea (trim adjacent template-source whitespace), Handlebars' ~ token instead of Liquid's -.

What's deliberately absent

Feature Where it exists Why kBars doesn't have it
Block helpers — a registered function that receives the unrendered block body and decides whether/how many times to render it Handlebars kBars's block set (if/unless/each/with) is fixed and built in; a custom transform can only post-process an already-resolved value, never control block rendering. There is no registration hook equivalent to Handlebars.registerHelper for block-level control.
Subexpressions(helper arg) nested anywhere a helper argument is expected Handlebars kBars allows a parenthesized expression chain as a transform argument (\| append: (title \| upcase)) and as an operand of a binary expression (a and (b or c); see Expressions), but not as a general nesting mechanism anywhere a helper call would go — there is no helper-call syntax to nest inside.
Lambdas — a context value that is itself a function, invoked with the section's unrendered text Mustache Not supported; every kBars context value is data, never executable.
Partial parameters ({{> partial param=value}}) Handlebars kBars partials take at most one context argument — no named parameters. See Partials.
Global mutable assignment — a binding with no explicit scope, visible everywhere for the rest of the render Liquid ({% assign %} is render-global by default) kBars requires every {{= }} target to name @env or @local explicitly — there is no unscoped third option.
Unparenthesized multi-operator chaining{% if a and b or c %} with no grouping Liquid A kBars expression is a single operand or exactly one binary operator; combining more than one operator always requires parentheses around one side, e.g. {{#if a and (b or c) }} — see Expressions. There is no implicit operator precedence to fall back on.
Scientific-notation number literals in source (1e10) Liquid, Handlebars (as JS numbers) A kBars number literal is -?[0-9]+(\.[0-9]+)? — no exponent syntax. Rendered output still uses full ECMA-262 formatting for values that arrive already large — see Number Rendering.

The truthiness trap

If you're porting from Liquid specifically, this is the difference most likely to silently change behavior: Liquid treats 0, "" (empty string), and an empty array as truthy — only nil and false are falsy. kBars's rule (shared with Handlebars) is stricter: {{#if}}/{{#unless}} and and/or treat null, numeric 0, false, "", and an empty list as falsy; everything else — including an empty struct {} — is truthy. A Liquid template relying on {% if count %} being true for count = 0 needs an explicit comparison in kBars: {{#if count != 0}}. See Expressions for the full rule.

Where to next

  • Writing Templates — the full page-by-page tour, if you'd rather read start to finish than jump in from a comparison table.
  • Template Basics — delimiters, comments, raw blocks, whitespace trimming, all from scratch rather than by comparison.
  • Custom Transforms — the closest kBars equivalent to a Handlebars helper or Liquid filter, worked end to end, if you're also building the application.