Express.js Setting Up Handlebars

Handlebars is one of the most popular templating engines for Node.js. It allows you to create dynamic HTML pages by combining static HTML with data from your Express backend. Unlike other engines that mix heavy JavaScript into your HTML, Handlebars is "logic-less," meaning it keeps your views clean and easy to maintain by using simple tags like {{variable}}.

Developer Tip: Template engines like Handlebars are essential for Server-Side Rendering (SSR). They help with SEO because the final HTML is generated on the server before being sent to the browser, making it easier for search engines to crawl your content.

 

Key Features of Handlebars

  • Logic in Templates: While it aims to be logic-less, Handlebars provides built-in "helpers" for common tasks like #if for conditionals and #each for looping through arrays.
  • Template Partials: Avoid repeating code by creating reusable components like headers, navigation bars, and footers.
  • Layouts: Define a "master" page structure so you only have to write your <head> and <body> tags once.
  • Precompiled Templates: For high-traffic applications, Handlebars can be precompiled to deliver extremely fast response times.
Best Practice: Keep your templates focused on display logic only. If you find yourself writing complex calculations inside a template, move that logic into your Express route or a controller instead.

 

Steps to Set Up Handlebars in Express.js

Install Handlebars
To integrate Handlebars into an Express project, you need the express-handlebars wrapper. This package makes the two libraries work together seamlessly. Run this command in your project terminal:

npm install express-handlebars

Set Handlebars as the View Engine
Once installed, you need to tell Express that Handlebars will be responsible for rendering your files. Note that in recent versions of express-handlebars, the setup syntax requires calling the .engine() function specifically.

Watch Out: Ensure you use the correct syntax for your version. For version 6.x and above, you must destructure engine from the package.

Update your app.js or server.js with the following configuration:

const express = require('express');
const { engine } = require('express-handlebars');
const app = express();

// Configure the Handlebars engine
app.engine('handlebars', engine());
app.set('view engine', 'handlebars');
app.set('views', './views');
Common Mistake: Forgetting to set the views directory. By default, Express looks in a folder named /views, but it is always safer to define it explicitly using app.set('views', './views').

Create Views Folder
Your project structure should look like this to follow standard conventions:

/project-root
  /views
    /layouts
      main.handlebars
    index.handlebars
  app.js

Create Handlebars Templates
Inside the views folder, create an index.handlebars file. This file will contain the unique content for your home page.

Example views/index.handlebars:

<!DOCTYPE html>
<html>
<head>
    <title>{{title}}</title>
</head>
<body>
    <h1>Welcome to {{title}}!</h1>
    <p>Status: Application is running smoothly.</p>
</body>
</html>

Render Views in Express Routes
In your Express route, you use res.render(). The first argument is the filename (without the extension), and the second is an object containing the data you want to pass to the page.

Example route:

app.get('/', (req, res) => {
    res.render('index', { 
        title: 'My Express Application',
        layout: false // Disabling layouts for this simple example
    });
});
Developer Tip: You don't need to type res.render('index.handlebars'). Since you set the view engine to 'handlebars', Express automatically appends the extension for you.

Run the Application
Start your server to see the results:

node app.js

Navigate to http://localhost:3000. Handlebars will take the title variable from your route and inject it directly into the HTML.

 

Using Partials in Handlebars

Partials are "mini-templates" that you can drop into any page. They are perfect for elements that appear on every page, like a navigation menu or a footer.

Best Practice: Use partials for any HTML snippet that is used more than once. This follows the DRY (Don't Repeat Yourself) principle, making it much easier to update your site's design later.

Create a Partial Template
Create a file named header.handlebars inside a new folder at views/partials/:

<header style="background: #f4f4f4; padding: 10px;">
    <nav>
        <a href="/">Home</a> | <a href="/about">About</a>
    </nav>
</header>

Register the Partial in Your Application
When you initialize the engine, you can tell it where your partials are stored:

app.engine('handlebars', engine({
    partialsDir: __dirname + '/views/partials/'
}));

Include the Partial in Other Templates
To use a partial, use the > symbol followed by the filename:

{{> header}}
<h2>Main Content</h2>
<p>This content is specific to the current page.</p>

 

Passing Data to Handlebars Templates

Handlebars makes it incredibly easy to display complex data like arrays of products or user profiles.

Example of passing an object and an array:

app.get('/profile', (req, res) => {
    const data = {
        user: { name: 'John Doe', role: 'Admin' },
        items: ['Laptop', 'Mouse', 'Keyboard']
    };
    res.render('profile', data);
});

In views/profile.handlebars, you can access nested data and loop through lists:

<h1>User: {{user.name}}</h1>
<p>Role: {{user.role}}</p>

<ul>
    {{#each items}}
        <li>{{this}}</li>
    {{/each}}
</ul>
Watch Out: If a variable is missing in the data object you pass to res.render, Handlebars will simply render nothing (an empty string) rather than throwing an error. This can sometimes make debugging tricky.

 

Using Helpers in Handlebars

Helpers are custom functions that you can use inside your templates to format data or perform logic that Handlebars doesn't support out of the box.

Register a Helper
Suppose you want to display prices formatted as currency. You can define a helper during the engine setup:

app.engine('handlebars', engine({
    helpers: {
        formatCurrency: (amount) => {
            return '$' + amount.toFixed(2);
        }
    }
}));

Use the Helper in Templates
You call the helper by name, followed by the variable you want to process:

<p>Total Price: {{formatCurrency product.price}}</p>
Developer Tip: Many developers use helpers for date formatting (using libraries like dayjs) or to check user permissions before showing "Edit" or "Delete" buttons.

 

Summary

Setting up Handlebars in Express.js transforms your application from a static file server into a dynamic web platform. By mastering layouts, partials, and helpers, you can build scalable and maintainable front-ends. Remember to keep your folder structure organized and leverage the power of partials to keep your code clean. With Handlebars, you get a perfect balance of performance and simplicity for your Node.js projects.