Templating engines are powerful tools that allow you to generate dynamic HTML content in Node.js application. templating engines provide a clean syntax for injecting data into your markup and implementing dynamic content features likes loops, conditionals and partials.
Otherwise we have to manually concatenating string or using complex DOM manipulations.
Popular Node.js Templating Engines
EJS (Embedded JavaScript)
EJS is a simple templating language that uses plain JavaScript to generate HTML markup. It’s known for its minimal syntax and low learning curve.
Installation
npm install ejs
Basic Usage
const ejs = require('ejs');
const express = require('express');
const app = express();
app.set('view engine', 'ejs');
app.set('views', './views');
app.get('/', (req, res) => {
res.render('index', { title: 'Home', message: 'Welcome to EJS!' });
});
EJS Template Example (views/index.ejs)
<!DOCTYPE html>
<html>
<head>
<title><%= title %></title>
</head>
<body>
<h1><%= message %></h1>
<% if (users && users.length > 0) { %>
<ul>
<% users.forEach(function(user) { %>
<li><%= user.name %></li>
<% }); %>
</ul>
<% } else { %>
<p>No users found</p>
<% } %>
</body>
</html>
Advanced Features
Partials and Includes
Partials (or includes) allow you to reuse template coomponents across multiple pages
<%- include('partials/header', {title: 'My Page'}) %>
<h1>Page Content</h1>
<%- include('partials/footer') %>
EJS Custom Functions
With EJS, you can pass any function as part of your data object:
app.get('/profile', (req, res) => {
res.render('profile', {
user: { name: 'John', joined: '2023-01-15' },
helpers: {
formatDate: (date) => new Date(date).toLocaleDateString()
}
});
});
Then in your template:
<p>Member since: <%= helpers.formatDate(user.joined) %></p>
Best Practices
1. Separate Login from templates
Keep complex logic in yout controllers/routes and pass only the necessary data to your templates.
Avoid:
<% if (user.permissions.includes('admin') || (user.department === 'IT' && user.level > 3)) { %>
<!-- Admin content -->
<% } %>
Better:
// In your route/controller
const isAdmin = user.permissions.includes('admin') ||
(user.department === 'IT' && user.level > 3);
res.render('dashboard', { user, isAdmin });
<!-- In your template -->
<% if (isAdmin) { %>
<!-- Admin content -->
<% } %>
2. Use Template Caching
Most templating engines offers caching options to improve performance in production.
// For EJS
app.set('view cache', process.env.NODE_ENV === 'production');
3. Implement Error Handling
Wrap template rendering in try/catch block to handle rendering errors gracefully.
app.get('/profile', (req, res) => {
try {
res.render('profile', { user });
} catch (err) {
console.error('Template rendering error:', err);
res.status(500).send('Error rendering page');
}
});