Imagine you’re building a web application that sends personalized welcome emails to new users. Hardcoding the email content in your JavaScript files works for a small test, but as the user base grows, you need a way to manage dynamic content cleanly and efficiently. This is where Handlebars, a templating engine, comes in. It lets you define reusable templates and populate them with data, keeping your code organized and scalable. In this post, you’ll learn how to use Handlebars in Node.js to create templates, making tasks like generating HTML or text output straightforward and flexible.
Setting Up Handlebars in Node.js
To use Handlebars, you first need to integrate it into your Node.js project. Let’s walk through the setup process step by step.
Install Handlebars
Start by adding Handlebars to your project. Open your terminal and run:
npm install handlebars
This installs the handlebars package, which provides the core functionality for creating and rendering templates.
Basic Project Structure
Create a simple project structure to work with. Here’s an example:
project/
├── templates/
│ └── welcome.hbs
├── index.js
└── package.json
The templates
folder will hold your Handlebars files (with a .hbs
extension by convention), and index.js
will contain the logic to render them.
Creating Your First Template
Handlebars templates are text files with placeholders for dynamic data. These placeholders, called expressions, use double curly braces like {{name}}
. Let’s create a basic template.
Define the Template
In templates/welcome.hbs
, add the following:
<h1>Welcome, {{name}}!</h1>
<p>Thanks for joining us on {{date}}.</p>
Here, {{name}}
and {{date}}
are placeholders that will be replaced with actual values when the template is rendered.
Render the Template in Node.js
Now, let’s use Node.js to load and render this template. In index.js
, write:
import fs from 'fs';
import handlebars from 'handlebars';
const templateString = fs.readFileSync('./templates/welcome.hbs', 'utf8');
const template = handlebars.compile(templateString);
const data = {
name: 'Alex',
date: 'February 24, 2025'
};
const output = template(data);
console.log(output);
Run this with node index.js
, and you’ll see:
<h1>Welcome, Alex!</h1>
<p>Thanks for joining us on February 24, 2025.</p>
The compile function turns the template into a reusable function. You pass it an object (data
), and it replaces the placeholders with the corresponding values. This approach keeps your presentation separate from your logic, making it easier to update designs or reuse templates.
Working with Helpers and Logic
Handlebars isn’t just about simple replacements—it also supports logic through built-in helpers and custom ones you can define. This adds flexibility to your templates.
Using Built-in Helpers
Handlebars provides helpers like if
and each
for conditional logic and loops. For example, imagine you want to list user interests if they exist. Update welcome.hbs
:
<h1>Welcome, {{name}}!</h1>
{{#if interests}}
<p>Your interests:</p>
<ul>
{{#each interests}}
<li>{{this}}</li>
{{/each}}
</ul>
{{else}}
<p>No interests listed yet.</p>
{{/if}}
Then, in index.js
, adjust the data:
const data = {
name: 'Alex',
interests: ['coding', 'reading', 'hiking']
};
const output = template(data);
console.log(output);
This outputs:
<h1>Welcome, Alex!</h1>
<p>Your interests:</p>
<ul>
<li>coding</li>
<li>reading</li>
<li>hiking</li>
</ul>
The if
helper checks if interests
exists and has content, while each
loops over the array, using this
to reference each item.
Creating Custom Helpers
You can also define your own helpers. Suppose you want to capitalize the user’s name. In index.js
, register a helper before compiling:
import fs from 'fs';
import handlebars from 'handlebars';
handlebars.registerHelper('capitalize', (str) => {
return str.charAt(0).toUpperCase() + str.slice(1);
});
const templateString = fs.readFileSync('./templates/welcome.hbs', 'utf8');
const template = handlebars.compile(templateString);
const data = { name: 'alex' };
const output = template(data);
console.log(output);
Update welcome.hbs
to use it:
<h1>Welcome, {{capitalize name}}!</h1>
Output:
<h1>Welcome, Alex!</h1>
Custom helpers let you extend Handlebars to fit your needs, keeping templates clean while handling complex formatting in code.
Integrating with Express
For web developers, Handlebars pairs well with Express, a popular Node.js framework. Here’s how to set it up.
Install Express and Handlebars for Express
Run:
npm install express express-handlebars
The express-handlebars package adapts Handlebars for Express.
Configure Express
In index.js
, set up a basic server:
import express from 'express';
import { engine } from 'express-handlebars';
const app = express();
app.engine('hbs', engine({ extname: '.hbs' }));
app.set('view engine', 'hbs');
app.set('views', './templates');
app.get('/', (req, res) => {
res.render('welcome', { name: 'Alex' });
});
app.listen(3000, () => console.log('Server running on port 3000'));
Place welcome.hbs
in the templates
folder as before. Visiting http://localhost:3000
renders the template directly in the browser. The res.render
method compiles and sends the template with the provided data, streamlining web development.
Note: Set extname: '.hbs'
in the engine options to match your file extension, as Express defaults to .handlebars
.
Conclusion
As you can see, Handlebars makes it very easy to manage dynamic content for things like emails, HTML pages, or other text-based outputs. It also makes it easier to maintain and update content by separating the template from the logic.
I hope you found this article helpful. If you have any questions, please feel free to ask in the comments section below.
Top comments (0)