Using Handlebars on the server and client

Update: People have been asking me how to share their Handlebars partials on the client while only writing them in one place. You can read how to do that here.

This article talks about how to use Handlebars templates on the client and the server, and how to avoid some pitfalls while doing so.

Handlebars on the server

Handlebars is my view engine of choice in NodeJS. I like how it’s just HTML with curly braces and some helpers, as opposed to EJS and Jade which look significantly different to HTML. If you haven’t used Handlebars before, here’s what a simple template looks like:

<div class="entry">
  <div class="body">

When building an Express web app, I use express3-handlebars to set up the plumbing to use Handlebars as a view engine. It’s written by my good friend and colleague, Eric, who’s one of the best engineers that I’ve ever met. I highly recommend it. You can set it up fairly easily through npm.

npm install express3-handlebars

Check out the basic usage section for information on how to set it up within Express.

If you want to use Handlebars in an Express app, check out my node-boilerplate fork that sets all this up for you.

Handlebars on the client

If you use any JavaScript MV* framework (BackBoneJS, EmberJS, YAF, etc), you probably need a template library on the client-side too. Handlebars plays well with all of these frameworks. One of the great things about using Handlebars on the client is that you can share templates between the client and the server. You can do this by having storing templates in partials, and then using those partials both on the server, and through <script> tags on the client.

Client-side templates when using Handlebars on the server

If you’re using Handlebars on the client and the server, you’ll run into this issue where the client-side templates will be parsed by the view engine on the server. For example, you may have a file like this:

    <h1>My Page Title</h1>
    <!-- This template should be transformed into HTML by the server -->
    <div id="photoList" class="pure-g">
        {{#each photos}}
            <div class="photo pure-u-1-12" data-photo-id="{{id}}">
                <img class="pure-u-1" src="{{src}}">

   <!-- This template should not be touched. It's for the client -->
    <script type="text/x-handlebars" id="lightbox-template">
        <img class="lightbox-image" src="{{large}}">
        <div class="lightbox-meta">
            <a class="pure-button lightbox-link" href="{{url}}">View on Flickr</a>
            <button class="pure-button lightbox-link lightbox-hide">Hide</button>

When you view this on the browser, the tags ({{..}}) within <script id="lightbox-template"> will be parsed out. You’ll get something like this, which is useless:

<!-- I can't use this template on the client anymore!! -->
<script type="text/x-handlebars" id="lightbox-template">
    <img class="lightbox-image" src="">
    <div class="lightbox-meta">
        <a class="pure-button lightbox-link" href="">View on Flickr</a>
        <button class="pure-button lightbox-link lightbox-hide">Hide</button>

Fortunately, the fix for this is very simple, albeit not documented anywhere. Just add a \ in front of all the opening tags ({{). The \ will be parsed out during the compilation step, and you’ll have a perfectly usable template on the client.

<!-- Add a \ before the handlebars -->
<script type="text/x-handlebars" id="lightbox-template">
    <img class="lightbox-image" src="\{{large}}">
    <div class="lightbox-meta">
        <a class="pure-button lightbox-link" href="\{{url}}">View on Flickr</a>
        <button class="pure-button lightbox-link lightbox-hide">Hide</button>

Kudos to Eric for coming up with this solution!

  1. Thanks so much – the \ trick saved the day!!!

    I am liking the idea of using handlebars in Node and on the front end with Backbone – but the issue of the server pre-parsing the handlebar expressions was killing me!

  2. Hi there, thanks for the info.

    I use handlebars with backbone on the client side, and now I’m just beginning myself to work with Express and I’ve just found that Express 4 has arrived. Will this solution be still aplicable to Express 4 or it’s version 3 specific? Thank you.

  3. Hi thanks for info.

    I am new to handle bars.
    I used your technique, works absolutely fine on client side but i need to do a date formatting. I am using this code.

    \{{datetime created_at format=”DD/MM/YYYY”}}

    gives me Uncaught Error: Missing helper: ‘dateFormat’

    Please help me resolve this issue.

    Thanks in advance!

  4. Hi Tilo, do you run into the problem of sharing hbs helper between client and server with this setup boilerplate, I find it hard to share it without duplicate the code, would like to hear if you have some insights, thx!

Comments are closed.