Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/expressjs/express/llms.txt

Use this file to discover all available pages before exploring further.

Template engines enable you to use static template files in your application. At runtime, the template engine replaces variables in a template file with actual values and transforms the template into an HTML file sent to the client.

Pug

Clean, whitespace-sensitive syntax

EJS

Embedded JavaScript templates

Handlebars

Minimal logic, mustache compatible

Setting Up a Template Engine

1

Install the template engine

npm install ejs
2

Configure Express

const express = require('express');
const path = require('path');

const app = express();

// Set views directory
app.set('views', path.join(__dirname, 'views'));

// Set view engine
app.set('view engine', 'ejs');
3

Create template files

Create a file at views/index.ejs:
<!DOCTYPE html>
<html>
  <head>
    <title><%= title %></title>
  </head>
  <body>
    <h1><%= header %></h1>
    <ul>
      <% users.forEach(function(user) { %>
        <li><%= user.name %> - <%= user.email %></li>
      <% }); %>
    </ul>
  </body>
</html>
4

Render the template

app.get('/', function(req, res) {
  res.render('index', {
    title: 'My App',
    header: 'Users',
    users: [
      { name: 'Tobi', email: 'tobi@example.com' },
      { name: 'Loki', email: 'loki@example.com' }
    ]
  });
});

EJS Templates

EJS (Embedded JavaScript) uses plain JavaScript in templates.

Basic Syntax

<!-- Output escaped value -->
<%= value %>

<!-- Output unescaped value -->
<%- value %>

<!-- JavaScript code -->
<% if (user) { %>
  <h2>Hello <%= user.name %></h2>
<% } %>

<!-- Loop through array -->
<ul>
  <% items.forEach(function(item) { %>
    <li><%= item %></li>
  <% }); %>
</ul>

Custom File Extensions

Register EJS with a custom extension:
const ejs = require('ejs');

// Use .html extension instead of .ejs
app.engine('html', ejs.__express);
app.set('view engine', 'html');

// Now you can use .html files
res.render('users.html', { users: users });
The .html extension makes templates easier to edit in IDEs with HTML syntax highlighting.

Pug Templates

Pug (formerly Jade) uses indentation-based syntax.
1

Install Pug

npm install pug
2

Configure Express

app.set('view engine', 'pug');
3

Create Pug template

Create views/index.pug:
doctype html
html
  head
    title= title
  body
    h1= header
    ul
      each user in users
        li= user.name + ' - ' + user.email

Handlebars Templates

Handlebars provides minimal logic templates.
npm install express-handlebars
const exphbs = require('express-handlebars');

app.engine('handlebars', exphbs.engine());
app.set('view engine', 'handlebars');
<!DOCTYPE html>
<html>
  <head>
    <title>{{title}}</title>
  </head>
  <body>
    <h1>{{header}}</h1>
    <ul>
      {{#each users}}
        <li>{{name}} - {{email}}</li>
      {{/each}}
    </ul>
  </body>
</html>

Custom Template Engines

You can register custom template engines:
const fs = require('fs');
const marked = require('marked');
const escapeHtml = require('escape-html');

// Register .md as a template engine
app.engine('md', function(path, options, fn) {
  fs.readFile(path, 'utf8', function(err, str) {
    if (err) return fn(err);
    
    // Parse markdown and replace variables
    const html = marked.parse(str).replace(/\{([^}]+)\}/g, function(_, name) {
      return escapeHtml(options[name] || '');
    });
    
    fn(null, html);
  });
});

app.set('view engine', 'md');

app.get('/', function(req, res) {
  res.render('index', { title: 'Markdown Example' });
});

Layouts and Partials

<!-- views/header.ejs -->
<header>
  <h1><%= siteName %></h1>
</header>

<!-- views/index.ejs -->
<%- include('header', { siteName: 'My Site' }) %>
<main>
  <p>Content here</p>
</main>
<%- include('footer') %>
//- views/layout.pug
doctype html
html
  head
    title= title
  body
    block content

//- views/index.pug
extends layout

block content
  h1 Welcome
  p This is the index page

Passing Data to Templates

// Pass individual values
res.render('index', {
  title: 'My Page',
  user: req.user
});

// Use res.locals for values available in all templates
app.use((req, res, next) => {
  res.locals.siteName = 'My Website';
  res.locals.currentUser = req.user;
  next();
});
Use res.locals to set variables that should be available in all templates, such as the current user or site configuration.

Caching Templates

Enable view caching in production to improve performance:
if (app.get('env') === 'production') {
  app.enable('view cache');
}

Best Practices

  • Escape user input to prevent XSS attacks
  • Use partials/includes for reusable components
  • Enable caching in production
  • Keep logic minimal in templates
  • Use layouts to avoid duplicating HTML structure
  • Set appropriate content type for non-HTML templates

Build docs developers (and LLMs) love