Multi-Engine Overview
binja uniquely supports multiple template engines through a unified API. All engines parse to a common AST and share the same runtime, filters, and optimizations.
Supported Engines
| Engine | Syntax | Use Case |
|---|---|---|
| Jinja2/DTL | {{ var }} {% if %} | Default, Python/Django compatibility |
| Handlebars | {{var}} {{#if}} | JavaScript ecosystem, Ember.js |
| Liquid | {{ var }} {% if %} | Shopify, Jekyll, static sites |
| Twig | {{ var }} {% if %} | PHP/Symfony, Drupal, Craft CMS |
Quick Comparison
| Feature | Jinja2 | Handlebars | Liquid | Twig |
|---|---|---|---|---|
| Variables | {{ x }} | {{x}} | {{ x }} | {{ x }} |
| Conditionals | {% if %} | {{#if}} | {% if %} | {% if %} |
| Loops | {% for %} | {{#each}} | {% for %} | {% for %} |
| Filters | {{ x|filter }} | {{ x }} | {{ x | filter }} | {{ x|filter }} |
| Comments | {# #} | {{! }} | {% comment %} | {# #} |
| Assignment | {% set %} | - | {% assign %} | {% set %} |
| Unescaped | {{ x|safe }} | {{{x}}} | - | {{ x|raw }} |
Direct Engine Usage
// Import specific enginesimport * as handlebars from 'binja/engines/handlebars'import * as liquid from 'binja/engines/liquid'import * as twig from 'binja/engines/twig'
// Handlebarsawait handlebars.render('Hello {{name}}!', { name: 'World' })
// Liquidawait liquid.render('Hello {{ name }}!', { name: 'World' })
// Twigawait twig.render('Hello {{ name }}!', { name: 'World' })MultiEngine API
For dynamic engine selection:
import { MultiEngine } from 'binja/engines'
const engine = new MultiEngine()
// Render with any engineawait engine.render('Hello {{name}}!', { name: 'World' }, 'handlebars')await engine.render('Hello {{ name }}!', { name: 'World' }, 'liquid')await engine.render('Hello {{ name }}!', { name: 'World' }, 'twig')await engine.render('Hello {{ name }}!', { name: 'World' }, 'jinja2')Auto-Detection
Detect engine from file extension:
import { detectEngine } from 'binja/engines'
const eng = detectEngine('template.hbs') // Handlebarsconst eng2 = detectEngine('page.liquid') // Liquidconst eng3 = detectEngine('page.twig') // Twigconst eng4 = detectEngine('page.html') // Jinja2 (default)Shared Features
All engines benefit from:
- 84+ built-in filters - Same filters work across all engines
- Runtime optimizations - Inline filter execution
- AOT compilation - Pre-compile for performance
- Autoescape - XSS protection by default
- Error handling - Consistent error messages
Migration Guide
From Handlebars.js
{{! Before: Handlebars.js }}{{#if user}} Hello {{user.name}}!{{/if}}
{{#each items}} <li>{{this}}</li>{{/each}}// After: binjaimport * as handlebars from 'binja/engines/handlebars'
const html = await handlebars.render(template, { user: { name: 'John' }, items: ['Apple', 'Banana']})From Liquid/Jekyll
{% comment %} Before: Liquid/Jekyll {% endcomment %}{% if user %} Hello {{ user.name }}!{% endif %}
{% for item in items %} <li>{{ item }}</li>{% endfor %}// After: binjaimport * as liquid from 'binja/engines/liquid'
const html = await liquid.render(template, { user: { name: 'John' }, items: ['Apple', 'Banana']})