Mustache vs Swig Templating Shootout!

At Shutterstock we recently went through the process of settling on a preferred templating language. We have lots of projects across different languages and platforms, and it was clear to the front end team that we would gain efficiency by investing in a single templating approach.

There are lots of templating languages out there, but two flavors stood out as obvious prospects: the Mustache family, and the Django family. There are strong pros and cons for each. Mustache has unmatched cross-platform support, while Django-inspired templating languages provide a more robust feature set.

We set out to compare implementations of slightly tricky tasks in both settings. Would we miss the extra features from the Django family? We used Node.js along with Swig (Django family) and Hogan (Mustache family) for our comparison.

Task #1: Position within a list

It happens from time to time that we’d like to know our index within a loop while in the context of templating. Let’s say we’re implementing some sort of thing with drag-and-drop, and we want to add a data attribute with the initial position of the element:

This is a little rough. The template itself looks great, but it’s regrettable to have to write the code that transforms names to add index alongside. It’s also a bit of a shame to have to mix formatting code in with business logic or controller logic.

Task #2: Currency Formatting

Often we want to show dollar amounts on the page. Let’s see how we do here with a very basic example where we want to show a list of items and a total price.

Formatting with Swig

Swig comes with some built-in filters, but not exactly any that would get us going here. That’s okay–we can define our own filter and register it with Swig:

Formatting with Mustache

Mustache requires a similar approach. We define a lambda to pass along with the data to render. Since we want to act on the rendered value here, we need to render the input first and then return a transformation of that.

This works, but it’s bulky and verbose having to set the price context, and then having to wrap the value with the formatter. One way or another you have to do some massaging before you pass the data to the template. We could also have just done the formatting right within the data structure too, but it would seem a shame to have to mix display formatting with data access.

Task #3: Place CSS at the top and JavaScript at the bottom

There’s a fairly common pattern where on a given page we may want to include a page-level CSS stylesheet, generate some markup, and then add event listeners at the end. From within a page template, ideally we’d like to put a <link> tag in the head and inject some JavaScript just before the closing </body> tag.

CSS at the top and JS at the bottom with Mustache

Mustache doesn’t directly support inheritance so we have to fake it. There are different ways to do it, none of them especially elegant. One way is to just always piece together the whole document using partials.

This is nicely explicit, but has its obvious drawbacks too. There are other approaches to consider as well. Some implementations support the concept of standard layouts. There’s also a proposal to update the Mustache spec to support inheritance. Hogan actually has unadvertised support for the proposed implementation. Yet another way is to use carefully crafted helpers in Handlebars. But basically when it comes to inheritance, Mustache support is a bit of a mess at the moment.

Other Considerations

Cross-Platform Support

We want to avoid having our templates lock us into a backend language or framework. Ideally if we want to migrate a project from Ruby/Sinatra to Node/Express, the last thing in the way should be the templates.

On a more practical level, we also want the flexibility to be able to share templates between the server and the client. For example, we may want to serve the first page of search results as rendered markup from the server, but then serve subsequent pages through AJAX, sending back JSON for the browser to interpolate into the same template that the server used. Both Mustache and Swig have solid in-browser implementations, so either fits the bill there.

Mustache actually has a formal spec, so you can be fairly sure that mustache templates that render with one implementation will likely render the same way in another. In real life though, since Mustache is very minimal, different implementations often add extra improvised features. Hogan adds nested accessors; Handlebars adds alternative control-flow syntax and helpers.

The Django family has decent cross-platform support, but implementations take wider liberties deviating from the original Django version. There’s Swig for JavaScript, Jinja for Python, Liquid for Ruby, DTLTemplate::Swig for Perl, and Twig for PHP. These implementations are all very strongly Django inspired, but again they diverge here and there.

Learning Curve

At Shutterstock we like to encourage people to reach outside their core disciplines and think holistically about what we’re all trying to do. For example, front-end developers might weigh in heavily on the direction of the product; back-end developers might suggest design directions; ops folk might suggest new business strategies, etc, etc.

So when it comes to templating, we want anyone to be able to dive in and find their way quickly, whether or not they have a background in front end development. A quick qualitative survey around the office found that relatively technical people had a much easier time picking up the Django style than they did learning the terse Mustache semantics.

Conclusion

In the end we went with the Django family — Swig, Twig, Liquid, etc. We still use Mustache here and there, but for projects of any decent size we find we really enjoy having the extra features and robustness in the Django templating languages.

Shutterbits is Shutterstock's engineering blog, where we talk about all that's fun and hard about running a website with millions of pieces of media, millions of daily page views, and millions of moving parts.

Get email updates

Subscribe to our blog for updates

Name:Email:

We’re Hiring

Come work for us! We're looking for smart, creative people who are passionate about writing code and solving problems.
Employment Opportunities ›