template engines performance dot mustache nunjucks dust swig (v11)

Revision 11 of this benchmark created by apfelbox on


Description

doT vs nunjucks vs mustache vs dust vs swig vs handlebars

Preparation HTML

<div id="main"></div>
<div id="wrapper"></div>

<script src="https://ajax.googleapis.com/ajax/libs/jquery/1/jquery.min.js"></script>
<script src="https://rawgithub.com/janl/mustache.js/master/mustache.js"></script>
<script src="http://rawgithub.com/mozilla/nunjucks/master/browser/nunjucks.min.js"></script>
<script src="http://rawgithub.com/olado/doT/master/doT.js"></script>
<script src="http://rawgithub.com/linkedin/dustjs/master/dist/dust-full.min.js"></script>
<script src="http://paularmstrong.github.io/swig/js/swig.min.js"></script>
<script src="http://rawgit.com/components/handlebars.js/v2.0.0/handlebars.min.js"></script>

<script id="mustache" type="text/x-mustache-template">
    <ul class="tweetSearchResultList">
        {{#results}}
            <li>
                <img src="{{profile_image_url}}" alt="{{from_user_name}}"/>
                <p>{{text}}</p>\
                <span>{{id}}</span
                <span>{{created_at}}</span>
            </li>
        {{/results}}
    </ul>
</script><!-- #mustache -->

<script id="nunjucks" type="text/x-nunjucks-template">
    <ul class="tweetSearchResultList">
        {% for item in results %}
            <li>
                <img src="{{ item.profile_image_url }}" alt="{{ item.from_user_name }}"/>
                <p>{{item.text}}</p>
                <span>{{item.id}}</span>
                <span>{{item.created_at}}</span>
            </li>
        {% endfor %}
    </ul>
</script><!-- #nunjucks -->

<script id="dot" type="text/x-dot-template">
    <ul class="tweetSearchResultList">
        {{~it.results :item:index}}
            <li>
                <img src="{{= item.profile_image_url }}" alt="{{= item.from_user_name }}"/>
                <p>{{=item.text}}</p>
                <span>{{=item.id}}</span>
                <span>{{=item.created_at}}</span>
            </li>
        {{~}}
    </ul>
</script><!-- #dot -->

<script id="dust" type="text/x-dust-template">
    <ul class="tweetSearchResultList">
        {#results}
            <li>
                <img src="{profile_image_url}" alt="{from_user_name}"/>
                <p>{text}</p>\
                <span>{id}</span
                <span>{created_at}</span>
            </li>
        {/results}
    </ul>
</script><!-- #dust -->

<script id="swig" type="text/x-swig-template">
    <ul class="tweetSearchResultList">
        {% for item in results %}
            <li>
                <img src="{{ item.profile_image_url }}" alt="{{ item.from_user_name }}"/>
                <p>{{item.text}}</p>
                <span>{{item.id}}</span>
                <span>{{item.created_at}}</span>
            </li>
        {% endfor %}
    </ul>
</script><!-- #swig -->

<script id="handlebars" type="text/x-handlebars-template">
    <ul class="tweetSearchResultList">
        {{#each results}}
            <li>
                <img src="{{profile_image_url}}" alt="{{from_user_name}}"/>
                <p>{{text}}</p>\
                <span>{{id}}</span
                <span>{{created_at}}</span>
            </li>
        {{/each}}
    </ul>
</script><!-- #handlebars -->

<script>
    var templates = {
        mustache: jQuery('#mustache').html()
        , nunjucks: jQuery('#nunjucks').html()
        , dot: jQuery('#dot').html()
        , dust: jQuery('#dust').html()
        , swig: jQuery('#swig').html()
        , handlebars: jQuery('#handlebars').html()
    };
    
</script>

Setup

var tweets;
        var template;
        
        tweets = {
            "completed_in":0.066
            ,"max_id":253753829672239104
            ,"max_id_str":"253753829672239104"
            ,"next_page":"?page=2&max_id=253753829672239104&q=china"
            ,"page":1
            ,"query":"china"
            ,"refresh_url":"?since_id=253753829672239104&q=china",
            "results":[
                {"created_at":"Thu, 04 Oct 2012 07:10:02 +0000","from_user":"rudsonjhdw","from_user_id":129806482,"from_user_id_str":"129806482","from_user_name":"leticia tamara da is","geo":null,"id":253753829672239104,"id_str":"253753829672239104","iso_language_code":"en","metadata":{"result_type":"recent"},"profile_image_url":"http:\/\/a0.twimg.com\/sticky\/default_profile_images\/default_profile_1_normal.png","profile_image_url_https":"https:\/\/si0.twimg.com\/sticky\/default_profile_images\/default_profile_1_normal.png","source":"&lt;a href=&quot;http:\/\/twitter.com\/&quot;&gt;web&lt;\/a&gt;","text":"The most common phrase in China \"Hey! You look familiar!\"","to_user":null,"to_user_id":0,"to_user_id_str":"0","to_user_name":null}
                ,{"created_at":"Thu, 04 Oct 2012 07:10:01 +0000","from_user":"sandru3","from_user_id":63535904,"from_user_id_str":"63535904","from_user_name":"sandruuuu!","geo":null,"id":253753827558313985,"id_str":"253753827558313985","iso_language_code":"en","metadata":{"result_type":"recent"},"profile_image_url":"http:\/\/a0.twimg.com\/profile_images\/2663559631\/bf31e812855a0e52415880ea8e84a362_normal.jpeg","profile_image_url_https":"https:\/\/si0.twimg.com\/profile_images\/2663559631\/bf31e812855a0e52415880ea8e84a362_normal.jpeg","source":"&lt;a href=&quot;http:\/\/www.echofon.com\/&quot;&gt;Echofon&lt;\/a&gt;","text":"RT @WTA: RT @WTA: Maria Sharapova reaches the China Open QFs w\/ a 60 62 win over Polona Hercog. Awaits winner of Kerber\/Wozniacki. #WTA http:\/\/t. ...","to_user":null,"to_user_id":0,"to_user_id_str":"0","to_user_name":null}
                ,{"created_at":"Thu, 04 Oct 2012 07:10:00 +0000","from_user":"BlGBlRD","from_user_id":223682306,"from_user_id_str":"223682306","from_user_name":"Big Bird","geo":null,"id":253753824504864768,"id_str":"253753824504864768","iso_language_code":"en","metadata":{"result_type":"recent"},"profile_image_url":"http:\/\/a0.twimg.com\/profile_images\/2678588911\/e9460b8843f561d0c4326852e9502a8a_normal.jpeg","profile_image_url_https":"https:\/\/si0.twimg.com\/profile_images\/2678588911\/e9460b8843f561d0c4326852e9502a8a_normal.jpeg","source":"&lt;a href=&quot;http:\/\/twitter.com\/&quot;&gt;web&lt;\/a&gt;","text":"I better go find a safe place to hide before Mitt Romney chops me up into little pieces and sells me off to create jobs in China. :(","to_user":null,"to_user_id":0,"to_user_id_str":"0","to_user_name":null}
                ,{"created_at":"Thu, 04 Oct 2012 07:10:00 +0000","from_user":"irra01010302","from_user_id":318970932,"from_user_id_str":"318970932","from_user_name":"Lee Kyuyeon\u2665","geo":null,"id":253753822076342273,"id_str":"253753822076342273","iso_language_code":"ja","metadata":{"result_type":"recent"},"profile_image_url":"http:\/\/a0.twimg.com\/profile_images\/2644336139\/233bd701fb824793c7bbf6638337dab5_normal.jpeg","profile_image_url_https":"https:\/\/si0.twimg.com\/profile_images\/2644336139\/233bd701fb824793c7bbf6638337dab5_normal.jpeg","source":"&lt;a href=&quot;http:\/\/ubersocial.com&quot;&gt;UberSocial for BlackBerry&lt;\/a&gt;","text":"RT _GoodbyeDays: 121002 China-Korea Music Festival #KyuMin's back  http:\/\/t.co\/dv1kF0PB --- http:\/\/t.co\/E8i5Xgv1 and *whisper** (\u25e0\ufe3f\u25e0\u2606)","to_user":null,"to_user_id":0,"to_user_id_str":"0","to_user_name":null}
                ,{"created_at":"Thu, 04 Oct 2012 07:09:59 +0000","from_user":"OtherJesus","from_user_id":137240583,"from_user_id_str":"137240583","from_user_name":"k daniels","geo":null,"id":253753819194855424,"id_str":"253753819194855424","iso_language_code":"en","metadata":{"result_type":"recent"},"profile_image_url":"http:\/\/a0.twimg.com\/profile_images\/1270315391\/Photo_2_normal.jpg","profile_image_url_https":"https:\/\/si0.twimg.com\/profile_images\/1270315391\/Photo_2_normal.jpg","source":"&lt;a href=&quot;http:\/\/twitter.com\/download\/iphone&quot;&gt;Twitter for iPhone&lt;\/a&gt;","text":"Romney has the balls to say we need to stop borrowing money from China but the Internet is more worried about PBS.","to_user":null,"to_user_id":0,"to_user_id_str":"0","to_user_name":null}
                ,{"created_at":"Thu, 04 Oct 2012 07:09:58 +0000","from_user":"s_china_2","from_user_id":191720529,"from_user_id_str":"191720529","from_user_name":"chinatsu shiraishi","geo":null,"id":253753812953731073,"id_str":"253753812953731073","iso_language_code":"ja","metadata":{"result_type":"recent"},"profile_image_url":"http:\/\/a0.twimg.com\/profile_images\/2517129390\/y5zchzI2_normal","profile_image_url_https":"https:\/\/si0.twimg.com\/profile_images\/2517129390\/y5zchzI2_normal","source":"&lt;a href=&quot;http:\/\/twitter.com\/download\/android&quot;&gt;Twitter for Android&lt;\/a&gt;","text":"\u3069\u3093\u306a\u4eba\u3068\u53cb\u9054\u306b\u306a\u308a\u305f\u3044\u304b\uff1f","to_user":null,"to_user_id":0,"to_user_id_str":"0","to_user_name":null}
                ,{"created_at":"Thu, 04 Oct 2012 07:09:57 +0000","from_user":"DicholasNuncan","from_user_id":500352351,"from_user_id_str":"500352351","from_user_name":"Dick Nuncan","geo":null,"id":253753812190367744,"id_str":"253753812190367744","iso_language_code":"en","metadata":{"result_type":"recent"},"profile_image_url":"http:\/\/a0.twimg.com\/profile_images\/2587255425\/49z4wlwvqarxi8igree5_normal.jpeg","profile_image_url_https":"https:\/\/si0.twimg.com\/profile_images\/2587255425\/49z4wlwvqarxi8igree5_normal.jpeg","source":"&lt;a href=&quot;http:\/\/twitter.com\/&quot;&gt;web&lt;\/a&gt;","text":"@meowitsmaija I honestly don't think we will ever pay it back. And China knows it's not wise to go to war with us over it since we run NATO","to_user":"meowitsmaija","to_user_id":81961249,"to_user_id_str":"81961249","to_user_name":"Maija Cole","in_reply_to_status_id":253753106284826624,"in_reply_to_status_id_str":"253753106284826624"}
                ,{"created_at":"Thu, 04 Oct 2012 07:09:56 +0000","from_user":"deerleuhan","from_user_id":320617461,"from_user_id_str":"320617461","from_user_name":"dinyu","geo":null,"id":253753806930710528,"id_str":"253753806930710528","iso_language_code":"ko","metadata":{"result_type":"recent"},"profile_image_url":"http:\/\/a0.twimg.com\/profile_images\/2664962425\/b4a9b1f94d85ff4ec4ef3135c01c3cbd_normal.jpeg","profile_image_url_https":"https:\/\/si0.twimg.com\/profile_images\/2664962425\/b4a9b1f94d85ff4ec4ef3135c01c3cbd_normal.jpeg","source":"&lt;a href=&quot;http:\/\/m.dabr.co.uk&quot;&gt;Dabr&lt;\/a&gt;","text":"RT @ohappybubbleo: RT @ohappybubbleo: 121002 China-Korea Festival #LUHAN - Beacuse of you, I can show you my everything.\u2764 http:\/\/t.co\/IiNzb2jl  \ub354 \ub9ce\uc740 \uc0ac\uc9c4\uc740 \uc55e\uc73c ...","to_user":null,"to_user_id":0,"to_user_id_str":"0","to_user_name":null}
                ,{"created_at":"Thu, 04 Oct 2012 07:09:55 +0000","from_user":"timiacono","from_user_id":125448978,"from_user_id_str":"125448978","from_user_name":"Tim Iacono","geo":null,"id":253753801322930176,"id_str":"253753801322930176","iso_language_code":"en","metadata":{"result_type":"recent"},"profile_image_url":"http:\/\/a0.twimg.com\/profile_images\/1801769606\/tim_normal.jpg","profile_image_url_https":"https:\/\/si0.twimg.com\/profile_images\/1801769606\/tim_normal.jpg","source":"&lt;a href=&quot;http:\/\/twitterfeed.com&quot;&gt;twitterfeed&lt;\/a&gt;","text":"Debt and Real Estate in China: This Washington Post story serves as a timely reminder that all is not well in Ch... http:\/\/t.co\/VNqjhCBM","to_user":null,"to_user_id":0,"to_user_id_str":"0","to_user_name":null}
                ,{"created_at":"Thu, 04 Oct 2012 07:09:54 +0000","from_user":"Fhiros","from_user_id":212611036,"from_user_id_str":"212611036","from_user_name":"The Synyster Reaper","geo":null,"id":253753796642107392,"id_str":"253753796642107392","iso_language_code":"es","metadata":{"result_type":"recent"},"profile_image_url":"http:\/\/a0.twimg.com\/profile_images\/2444574177\/fxo62fo3d29cx60asx8c_normal.jpeg","profile_image_url_https":"https:\/\/si0.twimg.com\/profile_images\/2444574177\/fxo62fo3d29cx60asx8c_normal.jpeg","source":"&lt;a href=&quot;http:\/\/twitter.com\/&quot;&gt;web&lt;\/a&gt;","text":"RT @EresCurioso: RT @EresCurioso: Matar a un oso panda en China se castiga con la muerte","to_user":null,"to_user_id":0,"to_user_id_str":"0","to_user_name":null}
                ,{"created_at":"Thu, 04 Oct 2012 07:09:53 +0000","from_user":"Avatti","from_user_id":258781722,"from_user_id_str":"258781722","from_user_name":"Avatti Consulting","geo":null,"id":253753793810952192,"id_str":"253753793810952192","iso_language_code":"en","metadata":{"result_type":"recent"},"profile_image_url":"http:\/\/a0.twimg.com\/profile_images\/1672042358\/Avatti_Logo_Twitter_normal.png","profile_image_url_https":"https:\/\/si0.twimg.com\/profile_images\/1672042358\/Avatti_Logo_Twitter_normal.png","source":"&lt;a href=&quot;http:\/\/twitterfeed.com&quot;&gt;twitterfeed&lt;\/a&gt;","text":"PlattsOil: What impact will China and India's recent #gasoil price hikes have? Find out with Platts' Oil Roundta... http:\/\/t.co\/V6h6dEfX","to_user":null,"to_user_id":0,"to_user_id_str":"0","to_user_name":null}
                ,{"created_at":"Thu, 04 Oct 2012 07:09:53 +0000","from_user":"Aishhhwarya","from_user_id":50203978,"from_user_id_str":"50203978","from_user_name":"AISH,\u2665","geo":null,"id":253753792988852224,"id_str":"253753792988852224","iso_language_code":"en","metadata":{"result_type":"recent"},"profile_image_url":"http:\/\/a0.twimg.com\/profile_images\/2654759049\/63d3333c33900f66c2c336c4d9090278_normal.jpeg","profile_image_url_https":"https:\/\/si0.twimg.com\/profile_images\/2654759049\/63d3333c33900f66c2c336c4d9090278_normal.jpeg","source":"&lt;a href=&quot;http:\/\/twitter.com\/&quot;&gt;web&lt;\/a&gt;","text":"@Rachel__xoxo Did you watch the China episode ytd!? hahah, how was it!! :D","to_user":"Rachel__xoxo","to_user_id":341290950,"to_user_id_str":"341290950","to_user_name":"Rachel Chen"}
                ,{"created_at":"Thu, 04 Oct 2012 07:09:50 +0000","from_user":"andieacoustic","from_user_id":185732914,"from_user_id_str":"185732914","from_user_name":"Andie Gilmore","geo":null,"id":253753782540828672,"id_str":"253753782540828672","iso_language_code":"en","metadata":{"result_type":"recent"},"profile_image_url":"http:\/\/a0.twimg.com\/profile_images\/2672219278\/84fa38e958db77d8407d8842938d92e5_normal.jpeg","profile_image_url_https":"https:\/\/si0.twimg.com\/profile_images\/2672219278\/84fa38e958db77d8407d8842938d92e5_normal.jpeg","source":"&lt;a href=&quot;http:\/\/twitter.com\/download\/android&quot;&gt;Twitter for Android&lt;\/a&gt;","text":"Just noticed I have a bump the size of China on my leg from softball. #thatscool","to_user":null,"to_user_id":0,"to_user_id_str":"0","to_user_name":null}
                ,{"created_at":"Thu, 04 Oct 2012 07:09:49 +0000","from_user":"UrbanArtists","from_user_id":37956350,"from_user_id_str":"37956350","from_user_name":"Urban Artists","geo":null,"id":253753775125307393,"id_str":"253753775125307393","iso_language_code":"en","metadata":{"result_type":"recent"},"profile_image_url":"http:\/\/a0.twimg.com\/profile_images\/2146140756\/picasion.com_b0b04a1faceace85bb8bf3ef722dbd23_normal.gif","profile_image_url_https":"https:\/\/si0.twimg.com\/profile_images\/2146140756\/picasion.com_b0b04a1faceace85bb8bf3ef722dbd23_normal.gif","source":"&lt;a href=&quot;http:\/\/twitter.com\/download\/iphone&quot;&gt;Twitter for iPhone&lt;\/a&gt;","text":"RT @blazeSNT: RT @blazeSNT: Trolling in china lol guangzhou city http:\/\/t.co\/dqJrVCQr","to_user":null,"to_user_id":0,"to_user_id_str":"0","to_user_name":null}
                ,{"created_at":"Thu, 04 Oct 2012 07:09:49 +0000","from_user":"LuciusHu","from_user_id":786442992,"from_user_id_str":"786442992","from_user_name":"Lucius","geo":null,"id":253753774479392768,"id_str":"253753774479392768","iso_language_code":"en","metadata":{"result_type":"recent"},"profile_image_url":"http:\/\/a0.twimg.com\/profile_images\/2562647642\/aukjnkx1ywco5oeuowsz_normal.jpeg","profile_image_url_https":"https:\/\/si0.twimg.com\/profile_images\/2562647642\/aukjnkx1ywco5oeuowsz_normal.jpeg","source":"&lt;a href=&quot;http:\/\/twitter.com\/tweetbutton&quot;&gt;Tweet Button&lt;\/a&gt;","text":"Twitter: \u2018biggest in China\u2019, report | beyondbrics | http:\/\/t.co\/rL0q7Pu0 http:\/\/t.co\/1FIZYj2t","to_user":null,"to_user_id":0,"to_user_id_str":"0","to_user_name":null}
            ]
            ,"results_per_page":15
            ,"since_id":0
            ,"since_id_str":"0"
        };
    
    // Dust precompiled
    var dust_precomp = dust.compile(templates.dust, 'intro_precomp');
    dust.loadSource(dust_precomp);
    
    // dot precompiled
    var dot_precomp = doT.template(templates.dot);
    
    // precompile (preparse) mustache
    Mustache.parse(templates.mustache);
    
    // nunjucks precompiled
    var nunjucks_precomp = new nunjucks.Template(templates.nunjucks);
    
    // Swig precompiled
    var swig_precomp = swig.compile(templates.swig);
    
    // precompile Handlebars
    var handlebars_precomp = Handlebars.compile(templates.handlebars);

Test runner

Ready to run.

Testing in
TestOps/sec
doT
var dot_temp = doT.template(templates.dot);
var dot_res = dot_temp(tweets);
ready
mustache
Mustache.clearCache();
Mustache.render(templates.mustache, tweets);
ready
nunjucks
var tmpl = nunjucks.compile(templates.nunjucks);
tmpl.render(tweets);
 
ready
dust.js
var dust_temp = dust.compile(templates.dust, 'intro');
dust.loadSource(dust_temp);
dust.render("intro", tweets, function(err, out) {
  //console.log(out);
});
ready
Swig
var swig_temp = swig.compile(templates.swig);
var swig_res = swig_temp(tweets);
ready
dust.js (precompiled)
dust.render("intro_precomp", tweets, function(err, out) {
  //console.log(out);
});
ready
doT (precompiled)
var dot_precomp_res = dot_precomp(tweets);
ready
nunjucks (precompiled)
nunjucks_precomp.render(tweets);
ready
Swig (precompiled)
var swig_precomp_res = swig_precomp(tweets);
ready
mustache (precompiled)
Mustache.render(templates.mustache, tweets);
ready
handlebars (precompiled)
handlebars_precomp(tweets);
ready
handlebars
var handlebars = Handlebars.compile(templates.handlebars);
handlebars(tweets);
ready

Revisions

You can edit these tests or add more tests to this page by appending /edit to the URL.