String Templating Considered Harmful

By Rich Harris

If you’re been programming for any length of time, you’ve probably read your fair share of ‘Considered Harmful‘ essays, and thus already know that what follows the headline is usually a stream of biased remarks and cherry-picked evidence.

I can’t promise this will be any different. But the concepts we’re going to cover are things that I think the front end community should be talking about.

The tl;dr is this: generating HTML from string templates is an inefficient process that imposes unnecessary constraints on how we conceptualize web applications. You can take advantage of templates without the drawbacks if you use a library like Ractive.js or beta versions of frameworks such as Meteor and Ember. If you don’t need to use templating, React is also an excellent option.

Templating 101

There are a huge number of templating libraries available to JavaScript developers – see Garann Means’ template engine chooser for a few examples. The vast majority of these are string templating engines, which is to say that they take a string template as an input (which typically resembles HTML, except with placeholder tags) alongside some data (which fills the placeholder tags), and outputs another string:

var template = '<h1>Hello {{name}}!</h1>';
var data = { name: 'world' };

Mustache.render( template, data );
// -> '<h1>Hello world!</h1>'

In the example above we’re using mustache.js, an implementation of the excellent mustache templating language, variants of which can be found in many places. It’s justifiably popular – you can learn it in seconds, and it is (I think) attractive, readable and concise. The existence of a formal specification has enabled alternative implementations such as Hogan.js to compete on code size and performance.

And developers love templates with good reason. Not all of them – Templating Languages Considered Harmful by Pete Hunt of the React core team makes a thoughtful case against templates – but enough of us that they’re not going away any time soon.

So why is string templating inefficient?

Generating HTML from a template and some data isn’t a particularly onerous task. The inefficient part is what you have to do with that HTML.

Suppose you have a piece of UI that represents changing data:

<div class='score'>
    <p>Current score: <strong>{{currentScore}}</strong></p>
    <p>High score: <strong>{{highScore}}</strong></p>

In our hypothetical shoot-em-up, the currentScore property is likely to change frequently. The highScore property might change with it if we’re doing well, but during many games it won’t change at all. Nevertheless, when we re-render the template and insert it into the document with something like score.innerHTML = rendered or $score.html(rendered), whatever is currently in the DOM will get discarded every time the score changes! In this example that includes a <div>, two <p> elements and two <strong>s, four text nodes and an attribute node (the class).

And that’s a fairly trivial example. As templates become larger, the amount of stuff that needs to be destroyed with each re-render grows – and that means extra work for the garbage collector. It’s slow and wasteful, and we haven’t even talked about what happens when you need to listen to DOM events on those nodes.

Updating views by inserting freshly rendered HTML into the DOM is like knocking your house down and rebuilding it when all you really needed to do was clean your windows.

Show me the evidence

Perhaps you’ve read that innerHTML is faster than DOM manipulation (in old versions of IE it is, but in modern browsers DOM manipulation is much faster), or that we’re not talking about a significant difference. Let’s look at some numbers.

Some time ago, Jeremy Ashkenas – the creator of Backbone, and all-round JavaScript hero – created a JSFiddle benchmark showing that Backbone’s data-binding performance was significantly better than that of Ember at the time.

The benchmark was forked to include React, which easily beat both competitors. Later, Erik Bryn updated the benchmark to include a development version of Ember he was working on (more on this below) that comfortably bested React.

You shouldn’t read too much into these benchmarks – it’s testing something which React, for example, is not optimized for. Other benchmarks would tell a different story. But there is one benchmark that we should find interesting – Backbone versus Backbone.

Open this JSFiddle. It’s a fork of the fork of the fork of Jeremy’s original. (I don’t doubt there are others). Try the implementations to see the magnitude of the difference. The ‘Backbone (fast)’ example is identical to the ‘Backbone’ example, except that instead of a render() method that uses string templating, it has an update() method that uses DOM manipulation. It’s much faster than continually reinserting big globs of HTML.

That’s a straw man – I don’t write my views like that!

Developers are intuitively aware of this problem. We don’t write big templates that cover an entire app – instead we write templates that describe much smaller parts, and combine them in code. Instead of writing a template for a list of todo items, we write a template for a single todo item, and create a view object for each one.

And this is exactly the problem. We end up thinking about our user interfaces atomically rather than holistically – the parts of our app we need to reason about most clearly are split into many different files. Maybe we’ve grown out of ‘jQuery spaghetti’, but in many cases it’s been replaced by MVC duct tape.

Perhaps you think it’s a good thing to write small, tightly focused templates – and you’d be right, some of the time. The point is that these architectural decisions shouldn’t be imposed on us by the limitations of the tools and techniques we’re working with.

What about DOM templating?

There is an alternative to string templating. DOM templating systems, such as those found in Knockout and Angular, put much of their data-binding in element attributes – Knockout’s data-bind or Angular’s ng-repeat, for example. These systems avoid the problem of having to continually trash the DOM.

But it comes at a price:

  • Because the data-binding instructions are read from the DOM, the template has to be renderable HTML, restricting the expressiveness of the templating language. The syntax is (opinion alert!) typically much less readable than that of string templating languages
  • You may have to work to prevent a FOUC – a ‘Flash Of Unbound Content’ – with hacks like ng-cloak
  • Server-side rendering is impossible without Rube Goldberg-esque systems involving JSDOM or PhantomJS
  • If you inspect the DOM, you’ll often find ‘data-binding cruft’ – invalid attributes like ng-model.

So what’s the answer?

We can have our cake and eat it. We can use string templates, with all their declarative convenience and expressive power, without any of the drawbacks we’ve discussed. How? By using a template parser that is aware of HTML as well as our templating language of choice.

Ractive.js, a UI library originally developed at, was a pioneer of this technique. Ractive uses a backwards-compatible variant of mustache (other languages may be supported in future), but rather than generating strings, its parser generates an abstract syntax tree.

This AST is later combined with data (typically plain old JavaScript objects, or POJOs) to construct a lightweight data-bound ‘parallel DOM’, which can run in the browser or on the server. Through this, it is able to make smart decisions about how to update the real DOM in the most conservative manner possible.

Because it only touches the parts of the DOM it needs to, you can write your templates in the way that makes the most sense for your app, without having to worry about the performance headaches of constantly trashing the DOM or the code headache of wiring up a plethora of view objects.

I won’t go into more detail about the project – you can learn it in 60 seconds here – other than to note that we also pioneered the idea of markup-driven data visualization, which was previously impossible since there’s no SVG equivalent of innerHTML.

But it’s a technique that’s about to become a lot more popular. Meteor, the full-stack JavaScript framework, has developed a library called Blaze which uses similar techniques, parsing string templates into a domain-specific language. Meanwhile Ember will shortly announce availability of HTMLBars (probably not its final name), an HTML-aware version of Handlebars. Apart from being largely responsible for the drastic performance improvements seen in the benchmarks above, it means Ember users now have a much nicer syntax to work with.

The future

I believe that variations on this technique represent the future of building user interfaces on the web. It’s proven to be a robust, performant, and infinitely flexible approach – and one that doesn’t demand that developers learn strange new concepts in order to become productive.

If you want to be part of that future and help build it, come on over to GitHub and join our (brand new) mailing list. You can follow @RactiveJS on Twitter.


An Interview with Thomas Palef on Creating HTML5 Games

Creating Sound with the Web Audio API and Oscillators


49 thoughts on “String Templating Considered Harmful”

    • Thanks Alisson – Vue.js is indeed a very promising library. It’s small and clean (the author was kind enough to cite Ractive.js as an influence) and performs well, and is very actively developed. However it uses a DOM templating approach, which puts it in the same category as Knockout and Angular – the design of these systems is tightly bound to the design of HTML itself (for better or worse), and it’s hard to render DOM-based templates on the server (which is problematic for SEO and initial page load performance). Having said all that I’m excited to see where Vue.js goes.

      • Why is it harder to render DOM-based templates on the server? Take PHP for example.

        PHP has native support for parsing HTML and XML. For the sake of performance optimisation, one could first do a simple Regex to find the parts of the document that need to be modified and parse only those parts instead of the entire document. Something like Symfony’s CSSSelector could be used to easily traversing the DOM in a jQuery-like fashion.

        Further, parts of a document that are unlikely to change often could be cashed, presenting a prerendered version of the data in most instances. This would further reduce the amount of HTML that needs to be rendered at runtime.

        What am I missing here? Sure, DOM parsing may be slower in backend than frontend and cut back on performance compared with regex based templating, but with the aforementioned performance optimisations I don’t really see why it’s not a feasible alternative to regex based templating on high performance production systems. Could you elaborate on your position?

      • The updating/changing of the html being discussed here is in reference to the live dom in the browser after your php has already rendered it out and sent it to the client. Templates are used to update the dom with javascript *without* having to re render the content on the server.

  1. I created a DOM templating engine called Teddy ( a while ago which seems to address all your concerns about DOM templating.

    I haven’t really done any promoting of it though, so it’s no surprise that nobody’s heard of it. πŸ˜‰

    But I’m curious how you think the approach I took with it stacks up against the more popular alternatives.

    • You should promote it! Using tag syntax for control flow is one of those ideas that’s completely novel yet totally obvious in hindsight. I love the fact that (in most editors) you would get code folding for free with that approach. Will take a closer look later when I have more time.

      I haven’t looked at the code, but the fact that you’re able to parse Teddy templates in Node makes me wonder if you could do the same thing on the client in browsers that don’t have a good DOMParser implementation? (I should probably make a confession – for all my railing against DOM templating, Ractive started out that way. It was only when I needed more robust SVG support that I actually implemented a parser!)

      • > Using tag syntax for control flow is one of those ideas that’s completely novel yet totally obvious in hindsight.

        Maybe not completely novel – Roxen, a very early, like 18 years ago (and very much ahead of its time in more ways than just this) web server had RXML, a inline tag based scripting / templating language:

        Ah, nostalgia! πŸ™‚

      • The server-side support depends on xmldom’s ( implementation of DOMParser and XMLSerializer. The xmldom project claims to have browser support too, but I haven’t yet checked to see how far back the browser support goes or generally how robust it is. If it (or some similar polyfill) runs in crazy things like IE8, then it might significantly extend Teddy’s browser support. This is definitely worth looking into. I’ll have to add that research to my list. πŸ™‚

        The familiar syntax was my primary motivation for making this. Getting syntax highlighting and code folding for free along with almost zero learning curve I felt was enough of a novel benefit to add to the overwhelming pile of templating engines out there. I haven’t really been promoting it because I can’t think of a way to do it without it seeming shameless self-promotey. (I’m open to suggestions!) It felt relevant to talk about in the context of this article though because it seems you and I share a lot of the same concerns about the more popular templating systems.

        The biggest caveat I think though is I can’t speak much to performance. I’ve never run benchmarks against other templating systems and it wouldn’t surprise me if more popular alternatives are much, much faster. Teddy’s performance is tied explicitly to how fast DOMParser and XMLSerializer perform in the target environment. On top of that, I’m sure there are plenty of ways to optimize the parsing algorithms I’m using. I consider it beta software. But it was fun to make, and it makes writing HTML templates a lot less annoying in my Node.js projects. πŸ™‚

      • I know how you feel about shameless self-promotion – it feels vulgar to shout ‘hey everybody look at this thing I made’. But I think ours is a community where it’s acceptable to share work that you’ve done. The thing I have to keep reminding myself is that we’re building things that solve other people’s problems – but only if they know about them!

        I’m immensely fortunate that I work for an organisation with a widely read developer blog (The Guardian) which meant I didn’t have to do too much evangelising before people heard about Ractive.

        If I’m in a position to offer advice, it would be to write about the problems you’ve identified and solved – the motivations for building the tool, rather than the tool itself – because that answers the ‘why should I care?’ question that developers have. If a tool does its job well, other people will talk about it for you!

      • Tag syntax is not completely novel, ColdFusion has been doing it for some time. That said, CF is server based and this is both client or server. Eric, I like that you try simplify and and really not re-invent. Would be interesting to see this extended to be used with other frameworks.

        Too many frameworks trying to re-invent the wheel instead of working to improve the wheel.

      • @Kevin, I was just making the same ColdFusion parallels. Very, very similar syntax here, with the benefits of being both server and client-side capable. I’m going to have to look at this one further.

    • As the person who runs this site, I can say that I’d be interested in publishing an article on it if you are up for writing one. πŸ™‚

  2. One thing I noticed about the circle drawing jsFiddle is that it’s clocking each loop synchronously, which is… totally inaccurate because repaint can happen outside of the JavaScript event loop. The proper way to measure the actual time taken to render the change to to clock the loop asynchronously at the beginning of the next iteration.

    A fork of your fork using async measuring:
    I also have a fork that includes Vue.js (

    As you will notice, the majority of the time is spent on the repaint and the difference between implementation becomes much less significant. The only takeaway from this benchmark is that innerHTML/DOM thrashing is slow, and as long as data binding is implemented in a sane manner, it is almost never the bottleneck.

    The arguments against DOM templating are, as you said, pretty opinionated. Personally for me I much prefer working with real HTML and find it more readable. However, I do agree the real advantage of a virtual/parallel DOM implementation is the ability to render isomorphically on both client and server, and it is something most DOM-based templating solutions haven’t been able to properly address yet (although not impossible).

    • Thanks for providing those forks and for the clear explanation re benchmarking – that’s very interesting. I’ll take some time to internalise what you’re saying so that any new benchmarks I create don’t fall into the same trap.

      However my interest was less in the comparison between different tools, and more in the difference between Backbone-with-thrashing and Backbone-without-thrashing. (I think benchmarks often cause developers to focus on the wrong things – we should optimise for maintainability, developer productivity and happiness, and only then for microsecond gains in contrived scenarios. Though Vue.js does well on all those fronts, so please don’t take that as snark!). My whole point is that data binding *isn’t* implemented in a sane manner when it relies on overwriting the DOM with new string templates, and that that’s an approach that’s way too common.

      DOM-based templating provides a much better solution to the data-binding problem than string-based templating, certainly. I wouldn’t call FOUC and lack of a good isomorphism story ‘opinionated’, but I take your point that some people prefer real HTML. We disagree on that point – personally I don’t think control flow directives belong right next to element attributes, for example – but that’s the kind of subject on which a diversity of opinions is to be encouraged.

      Keep on doing awesome stuff with Vue.js.

      • I dug into this benchmark and mentioned it on the mailing list (!topic/ractive-js/D9tnMhdPoXU) – I’m afraid to say it’s completely meaningless! The html being generated by the string templating engines (mustache, hogan and handlebars) isn’t actually *doing* anything, because it’s being inserted into an off-DOM node and never being queried in any way. For a browser, optimising that is trivial – it’s an apples to oranges comparison.

        Unfortunately that’s true of a lot of jsPerf benchmarks, and of benchmarks in general. I believe it’s much better to choose tools based on how productive you are working with them and the impact they have on your code, rather than on their performance in contrived situations. Otherwise we’re guilty of premature optimisation! (The benchmarks in this article are included primarily to show the difference between Backbone-with-innerHTML and Backbone-without-innerHTML, rather than to compare different tools.)

    • This comment not intended for publication… πŸ™‚ Sorry, the comment above was supposed to be a reply to my earlier comment about Roxen providing some additional context. Feel free to re-thread the comment, or edit my earlier one to include the link, or just delete this one, as it looks terribly out of place πŸ™‚

  3. I released a framework last week called Mithril ( ) that removes the HTML parsing step altogether by making the template be the AST.

    This bare-bones approach also allows better debuggability, and opens the doors for interesting FP techniques, among other things.

    Templating seems to be a hot button these days, but it’s unfortunate that it’s such a complex topic. Discussions about performance like this article are great, but it’s hard for non-framework devs to keep all the other facets of template design in their heads when trying to evaluate the bazillion choices in the market.

    • I’ve been playing with Mithril and it’s a beautiful design. Mithril seems to have almost no downsides (fast, small file size, full MVC pattern). It’d be great to see a comparison with Ractive. Leo – would you add this to your comparisons page?

  4. Another alternative, that automatically binds your Mustache template to your POJO is Features:

    – one function interface, simple to use, optimized for less typing
    – context-aware data-binding
    – synchronous and asynchronous computed properties (including setters)
    – routes (simple or specified via pattern)
    – XHR for communication with web-services and async partials, so usable for distributed applications

    Right now, consider it a prototype. It’s used in a couple of internal projects only. Next version, which won’t add new features, but will be smaller, faster and better test-covered is slowly cooking in the lab.

  5. Instead of re-rendering a string template all the time, I use string templates for the initial render, then once rendered use data binding to update the bits that needs to be updated.

  6. A tool is just a tool. Performance depends on how you use it. You can have backbone + handlebars + backbone.stickit to perform smart update of your properties and stay with string templating.

  7. It is also worth to mention another DOM render engine with
    – nice syntax
    – components – custom tag handlers
    – dualbindings
    – performance
    – NodeJS support (when used at the server side, then HTML is built for the browsers) It brings much better application-startup performance.

    The greatest advantage of DOM based renderers is its combination with the MV** frameworks. The controllers and components receive DOM Nodes in render process not the in bootstrap process after html render. This gives much better performance and better manipulation possibilities.

  8. Thanks for the article and references. Very insightful. In my experience, the biggest bottleneck to development is not the templating method, its complexity. Tools can always be built around approaches, but they can’t be built around people. Give someone Handlebars, and perhaps a little Swag, and you’ve got a simple, easy-to-use templating language so straight-forward it will speed up the true bottleneck in any app: people.

    And while were (kinda) on the topic of Reactive Programming on the web, no discussion is complete without an honorary mention of Rivets.js library. Like Angular it uses attributes in markup, which can be customized for valid markup, but unlike HTMLBars, it’s not bound to a particular templating language. See it in action with ECO templates here:

  9. I really happy, that more and more developers start thinking about DOM-based templates as perspective way for their solutions. DOM is powerful thing and may give much more than strings.
    I see many readers promote their own libraries and solutions in comments. And I afraid I’ll be one of them πŸ™‚
    I had worked on this approach for some year, as part of basis.js framework ( ). And also we have an experiment of publishing basis.js template engine as separate library ( ).
    So, I made two more forks of tests… and added solutions on basis.js view and just using it’s templates. Funny but pure basis.js templates solution even a little bit faster than `Animated with nothing` πŸ™‚
    In both forks used, if possible, istead of new Date() – for more accurate results.
    – fork from test in article: Ractive 2-times slower than basis.js templates solution here, sorry πŸ˜‰
    – fork of Evan You test: I also add Ractive to this fork. The difference is not so huge, but still noticeable ~20-25%.
    But I believe you and others will optimize their solutions, it’s about time.

    Anyway, DOM-based templates is not only performance goal. It also gives us understanding about DOM fragment and more control over it. We had implemented template live update based in it. It means when template source is changed we replace old DOM fragment for new one (generated by new source), and move some nodes from old DOM fragment to new one (it may be root elements of nested views). And it’s without page reload. It’s possible only because DOM used and know about DOM nodes structure. So it boosts development workflow and make it more effective. Moreover it extends for themes (you change not just css, but “html” too) and others crazy things like view adaptations depending on sort of data and it’s amount.

    I believe DOM-based template engines is our nearby future.
    Thank you for article and approach promotion!

  10. Thanks for this write up. I can’t even begin to summarize how much this article covers. I really need to read it over again. Thanks for this write up. You helped me solve problems I didn’t even view as problems yet… yet alone to know they were solved!


    If you want loop performance, and high frame rates you should be doing all of your DOM manipulation in an animationFrame. Also, why go through a function that returns attributes in these contrived examples when you can read model attributes directly?

    In this fork Backbone Fast is avg. ~16ms 60 fps by doing all the DOM update work async.

  12. Speaking of tl;dr, I didn’t make it past your first, flawed example. When one speaks of a template, one usually is referring to a framework that simplifies reuse/multiplicity not some single-use scenario where one wants to dynamically update a (couple of) number(s) on screen. What you describe in that example is not a (good) template by any stretch of the imagination – it’s an example of an inexperienced developer blowing away the entire contents of a div simply to update a number within.

    When I use a string-based templates (Handlebars) it’s because I need to repetitively display data in the same fashion.

    To use your example, “Updating views by inserting freshly rendered HTML into the DOM is like knocking your house down and rebuilding it when all you really needed to do was clean your windows”:

    I agree wholeheartedly. But if you wanted to make a point about not knocking down a whole house simply to clean the windows you shouldn’t drag string templates into a discussion which is plainly about DOM manipulation (cleaning the windows) vs. house-destroying constructs like .innerHTML. What one has to do with the other is beyond me. As far as I can tell this article is about the misuse of string templates and javascript, not why string templates might be considered harmful.

    • With respect, I don’t understand it when commenters begin with ‘I didn’t read the article’ then proceed to address its flaws.

      1) Yes, inexperienced developers do that sort of thing, because a) they don’t know any better, since this isn’t an issue that gets discussed frequently enough and b) as a community we haven’t historically provided them with tools that are as easy to use as string templating engines.
      2) In fact, let’s strike out that ‘inexperienced’. I see experienced developers do that sort of thing all the time. Hell, the original Backbone example in the benchmark was written by Jeremy Ashkenas himself! It’s disingenuous to draw the dichotomy between DOM manipulation and .innerHTML when idiomatic Backbone view code involves the latter.
      3) String templates are declarative and easy to reason about; DOM manipulation is much more efficient. This article is about tools that give you the best of both worlds, rather than forcing you to compromise.

  13. I really like the intent of Ractive, I even spend several minutes in the interactive tutorial. But as someone who often builds on small libs, I’m really turned off by the feature creep. It seems like you should be able to export a nice utility with less than 10k lines. As it stands, I can’t even separate what I like of Ractive from the “noise.”

    • My instincts lean the same way, but ultimately you have to ask yourself why smaller is better. If everything else was equal, then smaller would *obviously* be better, but other things aren’t equal – all too often, smaller means you end up having to do more of the work yourself. One person’s feature bloat is another person’s sweet spot – as someone who builds heavily interactive apps on short deadlines for a living, I’d hate to have to reimplement bits of what Ractive does or get different smaller libraries working smoothly together, because that’s what I used to have to do and I’m vastly more productive now! The problems it solves aren’t trivial; any solution to those problems will involve a level of irreducible complexity under the hood.

      That said, finding ways of splitting more functionality out of the core library and into plugins is something we’d like to think about in future, and your thoughts and feedback on that process would always be very welcome.

  14. Hm, wanted to start a discussion on that on google+ before I found that, so I include the text of after a short
    Im fine with the article but I doubt about your “DOM templating” paragraph.
    I think if you forget about ng- ;), the “data-” markup is a perfect use case and I think readability/usability is better
    What I’m playing with? Think of “data-extend”, “data-include”, “data-bind”, “data-condition”
    or e.g “data-class” for non static css classes that extend the class attribute. (?)
    ( for reasons see )
    But this is just for the markup-usability, in case of performance string templates like dtl/mustache win as you can see below.

    Dual side templating, now sometimes called “holy grail rendering” by AirBNB at least, has become a very important concern for web developers.)
    — orig. post mentioned before:
    Dual-Side Templating – DTL vs. DOM or
    PERFORMANCE vs. usability
    Hey people, I would like to start a discussion on the current state of Dual-Side Javascript Templating:
    +Michael Mahemoff has the history here ::
    Time to add a new chapter – we can use two techniques in 2014:
    – replacement stuff like dtl
    .- cooler, certainly more usable stuff like the dom

    For +Redaktor’s “framework part” I compared both and realized that dom templating on node.js is around 8-12 times slower than a dtl enginge like swig.
    Node.js serverside rendering – reference template with logic :

    swig (dtl/mustache syntax)
    weld (jsdom)
    our alpha (jsdom, can do the same like swig with dom “data-” markup but is clientside lighter than weld, using a stateful reference store)

    “jsdom solutions” save us so much headaches
    but seem to be slow. So it is *performance vs. usability*
    What is more important in which use case?ο»Ώ

Comments are closed.