SkillAgentSearch skills...

Binja

High-performance multi-engine template system for Bun. Jinja2/DTL, Handlebars & Liquid support. 2-4x faster than Nunjucks, 160x with AOT. 84 filters, template inheritance, autoescape, debug panel.

Install / Use

/learn @egeominotti/Binja
About this skill

Quality Score

0/100

Supported Platforms

Universal

README

<h1 align="center">binja</h1> <p align="center"> <strong>High-performance Jinja2/Django template engine for Bun - 2-4x faster than Nunjucks</strong> </p> <p align="center"> <a href="https://egeominotti.github.io/binja/"><strong>📚 Documentation</strong></a> • <a href="#installation">Installation</a> • <a href="#quick-start">Quick Start</a> • <a href="#framework-adapters">Hono/Elysia</a> • <a href="#multi-engine-support">Multi-Engine</a> • <a href="#filters-84-built-in">Filters</a> </p> <p align="center"> <a href="https://www.npmjs.com/package/binja"><img src="https://img.shields.io/npm/v/binja?label=npm&color=10b981" alt="npm version"></a> <a href="https://www.npmjs.com/package/binja"><img src="https://img.shields.io/npm/dm/binja?color=10b981" alt="npm downloads"></a> <a href="https://github.com/egeominotti/binja/actions"><img src="https://github.com/egeominotti/binja/actions/workflows/ci.yml/badge.svg" alt="CI"></a> <a href="https://github.com/egeominotti/binja/blob/main/LICENSE"><img src="https://img.shields.io/badge/license-BSD--3--Clause-blue.svg" alt="BSD-3-Clause License"></a> </p> <p align="center"> <img src="https://img.shields.io/badge/bun-%23000000.svg?style=for-the-badge&logo=bun&logoColor=white" alt="Bun" /> <img src="https://img.shields.io/badge/TypeScript-007ACC?style=for-the-badge&logo=typescript&logoColor=white" alt="TypeScript" /> <img src="https://img.shields.io/badge/Django-092E20?style=for-the-badge&logo=django&logoColor=white" alt="Django Compatible" /> </p>

Why binja?

| Feature | Binja | Other JS engines | |---------|-----------|------------------| | Runtime Performance | ✅ 2-4x faster | ❌ | | AOT Compilation | ✅ 160x faster | ❌ | | Multi-Engine | ✅ Jinja2, Handlebars, Liquid, Twig | ❌ | | Framework Adapters | ✅ Hono, Elysia | ❌ | | Django DTL Compatible | ✅ 100% | ❌ Partial | | Jinja2 Compatible | ✅ Full | ⚠️ Limited | | Template Inheritance | ✅ | ⚠️ | | 84 Built-in Filters | ✅ | ❌ | | 28 Built-in Tests | ✅ | ❌ | | Debug Panel | ✅ | ❌ | | CLI Tool | ✅ | ⚠️ | | Autoescape by Default | ✅ | ❌ | | TypeScript | ✅ Native | ⚠️ | | Bun Optimized | ✅ | ❌ |


Benchmarks

Tested on Mac Studio M1 Max, Bun 1.3.5.

Two Rendering Modes

| Mode | Function | Best For | vs Nunjucks | |------|----------|----------|-------------| | Runtime | render() | Development | 2-4x faster | | AOT | compile() | Production | 160x faster |

Runtime Performance (vs Nunjucks)

| Benchmark | binja | Nunjucks | Speedup | |-----------|-------|----------|---------| | Simple Template | 371K ops/s | 96K ops/s | 3.9x | | Complex Template | 44K ops/s | 23K ops/s | 2.0x | | Multiple Filters | 246K ops/s | 63K ops/s | 3.9x | | Nested Loops | 76K ops/s | 26K ops/s | 3.0x | | Conditionals | 84K ops/s | 25K ops/s | 3.4x | | HTML Escaping | 985K ops/s | 242K ops/s | 4.1x | | Large Dataset | 9.6K ops/s | 6.6K ops/s | 1.5x |

AOT Compilation (Maximum Performance)

| Benchmark | binja AOT | binja Runtime | Speedup | |-----------|-----------|---------------|---------| | Simple Template | 14.3M ops/s | 371K ops/s | 39x | | Complex Template | 1.07M ops/s | 44K ops/s | 24x | | Nested Loops | 1.75M ops/s | 76K ops/s | 23x |


Installation

bun add binja

Quick Start

import { render } from 'binja'

// Simple rendering
const html = await render('Hello, {{ name }}!', { name: 'World' })
// Output: Hello, World!

// With filters
const html = await render('{{ title|upper|truncatechars:20 }}', {
  title: 'Welcome to our amazing website'
})
// Output: WELCOME TO OUR AMAZI...

Using Environment

import { Environment } from 'binja'

const env = new Environment({
  templates: './templates',  // Template directory
  autoescape: true,          // XSS protection (default: true)
})

// Load and render template file
const html = await env.render('pages/home.html', {
  user: { name: 'John', email: 'john@example.com' },
  items: ['Apple', 'Banana', 'Cherry']
})

AOT Compilation (Maximum Performance)

For production, use compile() for 160x faster rendering:

import { compile } from 'binja'

// Compile once at startup
const renderUser = compile('<h1>{{ name|upper }}</h1>')

// Use many times (sync, extremely fast!)
const html = renderUser({ name: 'john' })
// Output: <h1>JOHN</h1>

Production example:

import { compile } from 'binja'

// Pre-compile all templates at server startup
const templates = {
  home: compile(await Bun.file('./views/home.html').text()),
  user: compile(await Bun.file('./views/user.html').text()),
}

// Rendering is now synchronous and extremely fast
app.get('/', () => templates.home({ title: 'Welcome' }))
app.get('/user/:id', ({ params }) => templates.user({ id: params.id }))

Features

Variables

{{ user.name }}
{{ user.email|lower }}
{{ items.0 }}
{{ data['key'] }}

Conditionals

{% if user.is_admin %}
  <span class="badge">Admin</span>
{% elif user.is_staff %}
  <span class="badge">Staff</span>
{% else %}
  <span class="badge">User</span>
{% endif %}

Loops

{% for item in items %}
  <div class="{{ loop.first ? 'first' : '' }}">
    {{ loop.index }}. {{ item.name }}
  </div>
{% empty %}
  <p>No items found.</p>
{% endfor %}

Loop Variables

| Variable | Description | |----------|-------------| | loop.index / forloop.counter | Current iteration (1-indexed) | | loop.index0 / forloop.counter0 | Current iteration (0-indexed) | | loop.first / forloop.first | True if first iteration | | loop.last / forloop.last | True if last iteration | | loop.length / forloop.length | Total number of items | | loop.parent / forloop.parentloop | Parent loop context |

Template Inheritance

base.html

<!DOCTYPE html>
<html>
<head>
  <title>{% block title %}Default Title{% endblock %}</title>
</head>
<body>
  {% block content %}{% endblock %}
</body>
</html>

page.html

{% extends "base.html" %}

{% block title %}My Page{% endblock %}

{% block content %}
  <h1>Welcome!</h1>
  <p>This is my page content.</p>
{% endblock %}

Include

{% include "components/header.html" %}
{% include "components/card.html" with title="Hello" %}

Set Variables

{% set greeting = "Hello, " ~ user.name %}
{{ greeting }}

{% with total = price * quantity %}
  Total: ${{ total }}
{% endwith %}

Filters (84 Built-in)

binja includes 84 built-in filters covering both Jinja2 and Django Template Language.

String Filters (26)

| Filter | Description | Example | |--------|-------------|---------| | upper | Uppercase | {{ "hello"\|upper }}HELLO | | lower | Lowercase | {{ "HELLO"\|lower }}hello | | capitalize | First letter uppercase | {{ "hello"\|capitalize }}Hello | | capfirst | First char uppercase | {{ "hello"\|capfirst }}Hello | | title | Title case | {{ "hello world"\|title }}Hello World | | trim | Strip whitespace | {{ " hi "\|trim }}hi | | striptags | Remove HTML tags | {{ "<p>Hi</p>"\|striptags }}Hi | | slugify | URL-friendly slug | {{ "Hello World!"\|slugify }}hello-world | | truncatechars | Truncate to N chars | {{ "hello"\|truncatechars:3 }}hel... | | truncatewords | Truncate to N words | {{ "a b c d"\|truncatewords:2 }}a b... | | truncatechars_html | Truncate preserving HTML | {{ "<b>hi</b> world"\|truncatechars_html:5 }} | | truncatewords_html | Truncate words in HTML | {{ "<p>a b c</p>"\|truncatewords_html:2 }} | | wordcount | Count words | {{ "hello world"\|wordcount }}2 | | wordwrap | Wrap at N chars | {{ text\|wordwrap:40 }} | | center | Center in N chars | {{ "hi"\|center:10 }} hi | | ljust | Left justify | {{ "hi"\|ljust:10 }}hi | | rjust | Right justify | {{ "hi"\|rjust:10 }} hi | | cut | Remove substring | {{ "hello"\|cut:"l" }}heo | | replace | Replace substring | {{ "hello"\|replace:"l","x" }}hexxo | | indent | Indent lines | {{ text\|indent:4 }} | | linebreaks | Newlines to <p>/<br> | {{ text\|linebreaks }} | | linebreaksbr | Newlines to <br> | {{ text\|linebreaksbr }} | | linenumbers | Add line numbers | {{ code\|linenumbers }} | | addslashes | Escape quotes | {{ "it's"\|addslashes }}it\'s | | format | sprintf-style format | {{ "Hi %s"\|format:name }} | | stringformat | Python % format | {{ 5\|stringformat:"03d" }}005 |

Number Filters (9)

| Filter | Description | Example | |--------|-------------|---------| | abs | Absolute value | {{ -5\|abs }}5 | | int | Convert to integer | {{ "42"\|int }}42 | | float | Convert to float | {{ "3.14"\|float }}3.14 | | round | Round number | {{ 3.7\|round }}4 | | add | Add number | {{ 5\|add:3 }}8 | | divisibleby | Check divisibility | {{ 10\|divisibleby:2 }}true | | floatformat | Format decimal places | {{ 3.14159\|floatformat:2 }}3.14 | | filesizeformat | Human file size | {{ 1048576\|filesizeformat }}1.0 MB | | get_digit | Get Nth digit | {{ 12345\|get_digit:2 }}4 |

List/Array Filters (22)

| Filter | Description | Example | |--------|-------------|---------| | length | List length | {{ items\|length }}3 | | length_is | Check length | {{ items\|length_is:3 }}true | | first | First item | {{ items\|first }} | | last | Last item | {{ items\|last }} | | join | Join with separator | {{ items\|join:", " }}a, b, c | | slice | Slice list | {{ items\|slice:":2" }} | | reverse | Reverse list | {{ items\|reverse }} | | sort | Sort list | {{ items\|sort }} | | unique | Remove duplicates | {{ items\|unique }} | | batch | Group into batches | `{{ items|batc

View on GitHub
GitHub Stars16
CategoryCustomer
Updated18d ago
Forks0

Languages

TypeScript

Security Score

90/100

Audited on Mar 16, 2026

No findings