Skip to content

Igo Dust ​

Introduction ​

Dust.js was a great templating engine, maintained and then abandoned by LinkedIn. After looking for an equivalent that was lightweight and performant, we ended up rewriting it from scratch — with zero dependencies and modern async/await patterns.

Key Features ​

  • Fully Async: Built with async/await, all rendering returns Promises
  • High Performance: Optimized compilation and rendering engine
  • HTML-safe by default: All output is HTML-encoded unless you opt out
  • Zero Dependencies: Lightweight and fast
  • Express Integration: Works as an Express view engine

Benchmark ​

We benchmark Igo Dust against other templating engines (Mustache, Handlebars, EJS, Pug, …) — see arnaudm/templating-engine-bench for the latest numbers.

Tooling ​

The VSCode extension for Igo Dust is available on the marketplace (also vendored as the syntax grammar in this site).

Differences from Dust.js ​

Igo Dust is not a drop-in replacement for Dust.js. It shares a similar syntax but has important differences:

1. Dot notation required in loops and sections

Inside a loop or section, you must use . to access properties of the current item:

js
// Template
{#users}{.name}{/users}

Without the dot, {name} looks up the root context, not the current item. This is the biggest difference from Dust.js.

You can also rename the iterator with it=:

js
{#users it="user"}{user.name}{/users}

2. No hierarchical scope chain

Dust.js searches up a scope chain to resolve variables. Igo Dust uses a flat context with explicit save/restore. Inside a section, only .property accesses the current context — there is no automatic fallback to parent contexts.

3. Empty arrays are falsy

In Igo Dust, [] evaluates to false in conditionals:

js
{?items}Has items{:else}No items{/items}
// With items = [] → "No items"

4. Async rendering only

All rendering methods return Promises. There is no callback-based API.

Quick Start ​

js
const dust = require('@igojs/dust');

const result = await dust.render('Hello, {name}!', { name: 'World' });
// => Hello, World!

Installation ​

bash
npm install @igojs/dust

Using with Express ​

js
const express = require('express');
const dust = require('@igojs/dust');
const app = express();

dust.configure({
  views: './views',
  cache: app.get('env') === 'production',
});

app.engine('dust', dust.engine);
app.set('view engine', 'dust');
app.set('views', './views');

app.get('/', (req, res) => {
  res.render('welcome/index', { name: 'World' });
});

app.listen(3000);

Template (views/welcome/index.dust):

html
<!DOCTYPE html>
<html>
<head><title>{title}</title></head>
<body>
  <h1>Hello, {name}!</h1>
</body>
</html>

Using the API ​

js
const dust = require('@igojs/dust');

// Render from string
const html = await dust.render('<h1>Hello, {name}!</h1>', { name: 'World' });

// Render from file
dust.configure({ views: './templates' });
const html = await dust.renderFile('template.dust', { name: 'World' });

Configuration ​

js
dust.configure({
  views:      './views',   // Template directory
  cache:      true,        // Cache compiled templates (recommended in production)
  htmlencode: true,        // HTML-encode all output (default: true)
  htmltrim:   true,        // Trim whitespace (default: true)
});
OptionTypeDefaultDescription
viewsstring'./views'Directory containing template files
cachebooleanfalseCache compiled templates
htmlencodebooleantrueHTML-encode all output (prevents XSS)
htmltrimbooleantrueRemove line breaks and trim whitespace

Next Steps ​

  • Basics — Syntax fundamentals
  • Loops — Iterating over arrays and objects
  • Logic — Conditional rendering
  • Helpers — Built-in and custom helpers
  • Filters — Output transformation
  • Partials — Template reuse and layouts
  • API — Full API reference

Released under the ISC license.