How to use template engines in Express.js?
Template Engines in Express.js
A template engine renders HTML on the server by combining a template file with dynamic data. Express supports many template engines via its app.set('view engine') configuration.
Popular Template Engines
| Engine | File Extension | Style |
|---|---|---|
| EJS | .ejs | HTML-like with <%= %> tags |
| Pug (Jade) | .pug | Indentation-based, no closing tags |
| Handlebars | .hbs | Logic-less {{ }} syntax |
| Nunjucks | .njk | Jinja2-like (Python-familiar) |
EJS — Most Common
bash
npm install ejsjs
// app.js
app.set('view engine', 'ejs');
app.set('views', './views'); // where template files livehtml
<!-- views/users.ejs -->
<!DOCTYPE html>
<html>
<head><title>Users</title></head>
<body>
<h1>Users (<%= users.length %>)</h1>
<ul>
<% users.forEach(user => { %>
<li><a href="/users/<%= user.id %>"><%= user.name %></a></li>
<% }) %>
</ul>
<% if (users.length === 0) { %>
<p>No users found.</p>
<% } %>
</body>
</html>js
// Route
app.get('/users', async (req, res) => {
const users = await User.findAll();
res.render('users', { users, title: 'User List' });
// ↑ template name ↑ data passed to template
});EJS Tags
| Tag | Purpose |
|---|---|
<%= value %> | Output (HTML-escaped) |
<%- value %> | Output (raw, unescaped HTML) |
<% code %> | JavaScript logic (no output) |
<%- include('partial') %> | Include another template |
Pug — Minimal Syntax
bash
npm install pugjs
app.set('view engine', 'pug');pug
//- views/users.pug
html
head
title Users
body
h1 Users (#{users.length})
ul
each user in users
li
a(href=`/users/${user.id}`) #{user.name}
if users.length === 0
p No users found.Layouts and Partials with EJS
html
<!-- views/partials/header.ejs -->
<header>
<nav>
<a href="/">Home</a>
<a href="/users">Users</a>
</nav>
</header>
<!-- views/layout.ejs -->
<!DOCTYPE html>
<html>
<head><title><%= title %></title></head>
<body>
<%- include('partials/header') %>
<main>
<%- body %>
</main>
</body>
</html>
<!-- views/users.ejs -->
<%- include('partials/header') %>
<ul>
<% users.forEach(u => { %>
<li><%= u.name %></li>
<% }) %>
</ul>Passing Data to Templates
js
// Data passed to res.render() is available in the template
res.render('profile', {
title: 'My Profile',
user: { name: 'Alice', role: 'admin' },
posts: [...],
isLoggedIn: true
});
// app.locals — available in ALL templates automatically
app.locals.appName = 'MyApp';
app.locals.year = new Date().getFullYear();
// res.locals — available in templates for THIS request
app.use((req, res, next) => {
res.locals.currentUser = req.user || null;
next();
});Template Engine vs JSON API
| Template Engine | JSON REST API | |
|---|---|---|
| Rendering | Server-side | Client-side (React, Vue) |
| Use case | Traditional MVC | SPA, mobile apps |
| SEO | Built-in | Needs SSR |
| Flexibility | Tightly coupled | Frontend-agnostic |
Summary
Use template engines for server-rendered HTML apps (MVC pattern). EJS is the most widely used — it's just HTML with JavaScript tags. For modern apps with React/Vue frontends, skip the template engine and build a JSON REST API instead.
Short Answer
Interview readyPremium
A concise answer to help you respond confidently on this topic during an interview.