Nunjucks calls itself “A rich and powerful templating language for JavaScript”, which sounds about right. It’s not intentionally super lightweight like Mustache or the slightly more robust (but still pretty light) Handlebars. It’s a full-on language, packed with all kinds of stuff you might want when writing templates.
You can run it in the browser, but you probably shouldn’t. This is meant to be run in Node.js and used to compile templates server side.
In other words: it’s a real fancy HTML preprocessor. Let’s look at some features that I think are particularly cool about Nunjucks.
Fair warning: this is highly subjective and based on only light experience! I’m only using like 10% of what Nunjucks is capable of here.

Nunjucks is a Node thing, so you install it with npm and work with it through the command line, build tools, and that whole world.
Here’s a single screenshot showing me run a Node script that renders a Nunjucks template:

nunjucks.render()
1. It’s just HTML
Notice that the file we passed to nunjucks.render()
was really just HTML with {{ handlebars }}
-like templating syntax inside. I named it `index.njk` but that isn’t really necessary, I just like being explicit about intention.
I’d bet there is a good contingent of front-end devs that prefer working in HTML even when the HTML is ultimately processed. I like Pug sometimes, but it’s a whitespace dependent language all to it’s own. Preferring Nunjucks is kinda like preferring ERB to HAML.
Here’s a perfectly legit template:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{{ page_title }}</title>
</head>
<body>
{% for feature in features %}
<div class="module">
<h3>{{ feature.name }}</h3>
<p>{{ feature.description }}</p>
</div>
{% endfor %}
</body>
</html>
What is features
? Data! You pass it to the render function.
nunjucks.render(
'index.njk', {
page_title: "Cool Product",
features: [
{
name: "Speed",
description: "It's fast."
},
{
name: "Reliability",
description: "You can count on it."
},
{
name: "Security",
description: "You don't have to worry about it."
}
]
}
);
You can imagine that data coming from a database or an API, I’m sure. You can also define data right in the view, as well, if needed.
<div>
{% set foo = "bar" %}
{{ foo }}
</div>
2. Includes
Sometimes I use a language just for the includes. For example, CodeKit has a language that is pretty much just for includes, because they know how useful they are.
Here’s how simple includes are in Nunjucks:
<body>
{% include "_header.njk" %}
<main>
...
</main>
{% include "_footer.njk" %}
</body>
3. Extends / Blocks
Extends take includes to the next level. Extends allow you to define a template document with “blocks” inside of it that are meant to take chunks of content.
Here’s a template with some includes, but also a block right in the middle:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>{{ page_title }}</title>
</head>
<body>
{% include "parts/_header.njk" %}
{% block main %}
This is the default content
{% endblock %}
{% include "parts/_footer.njk" %}
</body>
</html>
Now any other file can extend that template, and not need to worry about all that boilerplate HTML that comes along with likely all pages of the site. Our `index.njk`, for instance, becomes:
{% extends "parts/_template.njk" %}
{% block main %}
{% for feature in features %}
<div class="module">
<h3>{{ feature.name }}</h3>
<p>{{ feature.description }}</p>
</div>
{% endfor %}
{% endblock %}
I bet you can imagine what fleshing that out looks like. Perhaps multiple templates for different types of pages. More blocks, gives yourself an opportunity to pass in additional stylesheet or scripts. More blocks for areas of the site, like what goes in the sidebar and footer as well.
4. Macros
Speaking of taking templating to the next level, macros do that yet again.
Macros are like imports with parameters. Like functions! You give it some values and it returns some stuff for you.
Imagine a module that takes three values. For example sake, say a “color swatch” (as if we’re building a pattern library), that takes the color value, name, and notes.
We could build that like this:
{% macro cardSwatch(colorName, colorValue, colorNotes) %}
<div class="color-swatch-tile">
<div class="color-swatch"
style="background-color: {{ colorValue }};">
</div>
<div class="color-name">
{{ colorName }}
</div>
<div class="color-notes">
{{ colorNotes }}
</div>
</div>
{% endmacro %}
Now I can use that over and over:
{{ cardSwatch("brandColor", "#f06d06", "Our main color.") }}
{{ cardSwatch("brandHighlight", "#d0b000", "For callouts and highlights.") }}
{{ cardSwatch("grayDark", "#333333", "For things like code block backgrounds.") }}
Better still, I can move the macros into their own file/files and import them as needed. Here, I’ll import a macro
, extend
a template, and loop through colors
data calling a macro
:
{% from "macros/swatch.njk" import swatch %}
{% extends "parts/_template.njk" %}
{% block main %}
{% for color in colors %}
{{ swatch(color.color_name, color.color_value, color.color_notes) }}
{% endfor %}
{% endblock %}
CodePen Projects Supports Nunjucks
Yes indeed! Which is nice, because it requires zero setup. (You know about CodePen Projects, right?) Just name a file ending in `.njk` and CodePen will know to process it as Nunjucks.

Nunjucks with Gulp
Working locally with Nunjucks, you’ll almost certainly want a build tool like Gulp to help process the files. Fortunately there is gulp-nunjucks to make it even easier.
gulp.task('default', () =>
gulp.src('index.html')
.pipe(nunjucks.compile({
my_data: "is here"
}))
.pipe(gulp.dest('dist'))
);
Repo
I created one as I played with Nunjucks in the writing of this article.
This looks a heck of a lot like twig. Nice!
There’s a TwigJS: https://github.com/twigjs/twig.js :)
That’s because Nunjucks, Swig and Twig are inspired by Python’s Jinja.
In fact, Nunjucks tries to be quite close port of Jinja2 to JavaScript. Well, that’s something worth mentioning in the article.
If you are looking for a front-end JS templates that offers a lot of similar features, take a look at JSRender.
http://www.jsviews.com/#jsrplaying
Isn’t it just beautiful how similar client-side application frameworks and server-side templating frameworks can be? I mean, just look at that macro example. They might as well call them components, because that’s what they are! :)
(The beauty actually comes full circle with isomorphic frameworks. Anyone else get goosebumps thinking about this stuff?)
They’re not components, don’t be fooled by that. Macros are nothing more that parametrized strings, that’s all. What you put inside could even be plain text, JSON, Python code or whatever you want. (Although Nunjucks is designed to escape interpolated values for HTML.)
What’s worse is that you can easily test components, while testing macros is a totally different beast.
Just because it’s a parameterized string doesn’t mean we can’t consider it to be a component.
const Addition = (a, b) => `${a} + ${b} = ${a + b}`
Here’s another parameterized string. You might argue it’s just a function returning a string (just like Nunjuck’s macros!), but you know what I see? A component! :)
Drawing parallels like this is what makes web development so beautiful.
Well, to be more exact, macros are just functions, which always prints during render. That’s all. You can do whatever you want with it. Even write CSS.
Nunjucks macros as a Components even easier to test, because they are mostly static (except few rare exception, when you’re doing something async on client-side or triggering side-effects with macros).
Because of that, testing is very trivial.
If someone wondering how to do this, here is an example.
Here I’m actually testing Nunjucks custom global functions, but you can imagine that it will work in same way for macros.
For instance, if we have some “component”
blogPostPreview
:You might like the approach of https://atmin.github.io/funponent
Snapshot testing is a very basic way of testing, that’s not always what you’d want. In fact, I’d say it’s rarely what you want, because since macros are “static” this kind of tests brings little to no value. It’s like having a test like
it('should just work', ...)
.But there’s more than that. How do you get the code coverage of your macro tests? How do you apply linting or any method of quality check?
Snapshot testing is very efficient way to automate regression testing.
If your components are pure functions, which is a very achievable using Redux (not necessarily with React) or similar to decouple state, then as you evolve your component you collect new inputs and resulting snapshots and refactor with confidence you didn’t break anything.
You can test your reducers using snapshots, as well (they are pure functions).
Macros can be full-featured components. Just throw something like Pjax and let server fully manage client state. That won’t work efficiently for highly dynamic interactions, but huge number of apps can utilize this approach and dodge a lot of implementation complexity.
It can be useful, when macro has complex logic and multiple states. What else would you want to test in tool, which just spits out rendered HTML?
The is more a matter of tools. As far as I know, right now there is no coverage tools for Nunjucks (though, it’s possible to write one), and no linting tools. That’s right.
I don’t think that coverage tool is really needed thing for templating language, unless you’re crazy and putting too much logic into templates.
But yeap, I’d like to see linting tool, definately.
We actually used a version of this for our sports awards site. Super easy to work with on the front end.
I actually don’t recommend using advanced templating languages like Nunjucks (or Twig, or Swig, or Jinja2, which are all basically the same thing), because they’re just too powerful.
One might observe that there’s no such thing as being “too” powerful, since you can just avoid using certain features, but the simple fact that you can do those things will probably lead you to actually do those things.
Now, what’s wrong with Nunjucks? It allows you to write logic in your templates. Think about it: instead of filling the template with all the values it needs, Nunjucks allows you to manipulate raw data and extract those values. The problem here is that it’s much harder to debug and test.
Macros are definitely a no-go for me. But also its convoluted system of blocks, extensions, embedding and imports is just too much. Not to mention to extend all of this with custom filters, functions and checks.
I got aware of that while working with Symfony, which uses Twig by default. Heck, at that point you can straight out use PHP, which has actually been born as a templating engine!
When I switched to Handlebars, after getting the hang of it everything got simpler (and I still can extend the language, although I do that for a very small amount of cases).
From the GitHub page:
I am going with pugjs
Cool! Can’t wait for when we start configuring our JS using comment annotations like Symfony :)
It’s amazing! I’ve been waiting for this for many years! Thank you, Chris!
Thanks for this, I’ve been wanting to get started with nunjucks but found the documentation a bit much. Your guide is great!
I had found nunjucks whilst looking for a templating language for my gulp email templating workflow didn’t realise how powerful it was until I started playing with macros. So useful!
I’m glad that finally it has been featured on CSS-Tricks.
Nunjucks is extremely powerful templating based on solid and battle tested ideas of Jinja2.
In fact, at some point under lead of Carl Meyer it became very close port of Jinja2 to the point that same templates could be used both in JS and Python environments.
Even despite it lacks active maintainers, we still can’t find better alternative.
Nunjucks can look like nothing special at first glance in comparison to other well known templating languages (except quite elegant syntax and some nice features, like unpacking during loops), but the deeper you will get the harder will be to return to other templating languages.
And it’s one of the few asynchronous templating languages. This can be deal-breaking sometimes, especially if templating used on client-side and you need to deal with a lot of async tasks.
Nunjucks are quite well adapted to work in browsers, and initially it was developed as client-side templating language.
Nunjucks can be precompiled, so that you can drop compiler in production and run almost bare JavaScript as your templates with quite small footprint.
But, of course, for some complex tasks in modern age React or VueJS would give much more benefits and less headaches.
Well, in fact they are functions, which just always prints (if there are anything to print).
This means, that they can be used not only to print some HTML, but also to invoke some side effects or change data (if you’re crazy enough). Is it worth doing so? That’s whole another story.
But, obviously, the most straightforward way to use them is consider them an incarnation of a Component. We actively using this approach in Kotsu, as can be seen in built-in Kotsu Components.
In fact, I encourage to explore Kotsu templates, because over time they soaked quite a lot of expirience of developing based on Nunjucks. For instance, you can see Gettext-based l10n based on Nunjucks globals or seamlesly integrated Markdown.
Also for inspiration worth to check Nunjucks extensions we’re using in Kotsu. At complex projects some of those are invaluable.
I wish I could show our commercial projects, based on Nunjucks, but unfortunately, I can only tease what it can be like in statically-generated website with large catalog of production:
Our list of components:
And here is how clean looks category page layout, which generates very complex table with production, which includes a lot of real data-driven information:
All category pages simply extending it and providing some additional information to context to make page render with data we want to display (we’re using Front Matter for it, but it can be done without it):
At top can be seen Nunjucks global functions in form of selectors, which passing data and complex calculations (which should be kept out of templating) from Node app inside Nunjucks:
And this is how selectors, which are just plain JavaScript (CoffeeScript) looks like:
I hope this will give some inspiration to people wondering what exactly can be done with Nunjucks and how it looks on battle project :)
Ops, posting form stripped all images specified with markdown
![]()
.I’m posting once again, with plain urls to screenshots.
Our list of components: https://vgy.me/eZXlWq.png
And here is how clean looks category page layout, which generates very complex table with production, which includes a lot of real data-driven information: https://vgy.me/bh6N5r.png
All category pages simply extending it and providing some additional information to context to make page render with data we want to display (we’re using Front Matter for it, but it can be done without it): https://vgy.me/tIBxQZ.png
At top can be seen Nunjucks global functions in form of selectors, which passing data and complex calculations (which should be kept out of templating) from Node app inside Nunjucks: https://vgy.me/GKf05L.png
And this is how selectors, which are just plain JavaScript (CoffeeScript) looks like: https://vgy.me/uO8i5Z.png
I hope this will give some inspiration to people wondering what exactly can be done with Nunjucks and how it looks on battle project :)