nunjucks

A powerful, Jinja2-inspired templating engine for JavaScript, with inheritance, autoescaping, and async control.

Library
npm
v3.2.4
8,985stars
BSD-2-Clause

Repository Health

Pre-computed score based on development activity, maintenance, community, maturity, and trend momentum.How we score it →
49/100Fair
Development Activity4
Maintenance20
Community72
Maturity60
Momentum40

Technical Analysis

AI-assessed by reading the actual repository — architecture, code quality, innovation, and documentation.How we score it →
76/100Good
Architecture80
Code Quality78
Innovation70
Learning Curve75

Nunjucks is a full-featured templating engine for JavaScript, built by Mozilla and heavily inspired by Python’s Jinja2. It compiles templates to JavaScript for fast repeated rendering and runs identically in Node.js and in the browser, making it a natural fit for teams porting Jinja2-style templates to a JS stack or wanting one templating syntax shared across server and client.

Beyond basic variable interpolation and loops, Nunjucks supports template inheritance (extends/block), macros, custom filters and tags, asynchronous control flow for filters and extensions that need to hit a database or API mid-render, and autoescaping to guard against XSS by default. A dedicated Express integration and a precompiler for shipping templates as plain JS (avoiding a runtime compile step and eval-like execution in the browser) round out the toolkit.

What You Get

  • Template inheritance via extends/block and reusable macros
  • A configurable autoescaping engine to prevent XSS by default
  • Asynchronous filters, tests, and extensions via a callback/waterfall-based async API
  • Built-in loaders for the filesystem, the browser (via HTTP), and precompiled template bundles
  • A nunjucks-precompile CLI and precompiler API to ship templates as plain JS, skipping runtime compilation
  • First-class Express integration (nunjucks.configure(app)) as a view engine
  • An optional Jinja2 compatibility layer (installJinjaCompat()) for closer parity with Python templates

Common Use Cases

  • Server-side HTML rendering in Express apps that want Jinja2-style templates instead of EJS/Pug syntax
  • Sharing one templating syntax between a Python/Jinja2 backend and a JavaScript frontend or build pipeline
  • Precompiling templates at build time and shipping them to the browser as static JS bundles for fast client-side rendering
  • Generating emails, static site pages, or config/code files from data using inheritance and macros

Under The Hood

Architecture — Nunjucks follows a classic compile pipeline: lexer.js tokenizes template source, parser.js builds an AST of nodes.js node types, transformer.js performs AST transforms (e.g. hoisting async operations), and compiler.js (~1200 lines) walks the tree to emit a JavaScript rendering function as source text, which environment.js’s Template class then executes against a runtime (runtime.js) that provides context/frame variable lookups, autoescaping (markSafe/suppressValue), and error handling (handleError). Environment (extending an internal EmitterObj) owns the loader chain (FileSystemLoader, WebLoader, PrecompiledLoader from loaders.js), filter/test/global registries, and both sync and async render/renderString entry points; async rendering is driven by the a-sync-waterfall and asap packages so callback-based async filters and extensions compose correctly with the compiled template code.

Tech Stack — Pure JavaScript (93% of the codebase) with a small set of runtime dependencies: a-sync-waterfall and asap for async control flow, and commander for the nunjucks-precompile CLI (bin/precompile). chokidar is an optional peer dependency used only for filesystem template watching. The build uses Babel (@babel/preset-env targeting old browsers down to IE9 and Node 6) plus a custom Webpack bundling script (scripts/bundle.js) to produce the browser bundle declared in package.json’s browser field, reflecting the library’s dual Node/browser design goal.

Code Quality — The test suite is substantial (~6,500 lines across tests/api.js, compiler.js, parser.js, lexer.js, runtime.js, filters.js, loader.js, express.js, jinja-compat.js, and others, run with Mocha and instrumented with nyc/Istanbul for coverage), and includes 29 template fixture files for integration-style rendering tests. Code style is enforced via ESLint (eslint.config.js with the Airbnb extended config). Error handling is centralized through a TemplateError/handleError mechanism in runtime.js/lib.js that attaches line/column info to compile and render errors, which is a deliberate ergonomics choice for debugging templates.

API Design — The public surface is intentionally small and Jinja2-familiar: nunjucks.configure(), .render(), .renderString(), .compile(), plus addFilter/addGlobal/addExtension for customization, so developers coming from Jinja2/Django templates can be productive with almost no new concepts. The optional installJinjaCompat() compatibility shim and the precompiler’s parallel sync/async APIs add some surface-area complexity, but the common path (configure a loader, call render) requires very little boilerplate.

Join founders buildingwith open source

Opinionated takes, migration guides, cost-saving tips, and insights from the open source ecosystem.

Subscribe on Substack
Join 750+ subscribers

Search