Learn how to integrate Pug with Express.js to create dynamic, server-side rendered HTML pages. This tutorial guides you through setting up Pug, creating templates, and passing data from Express to Pug for efficient content rendering.
What is Pug?
Pug (formerly Jade) is a high-performance templating language for Node.js. It uses simplified, indentation-based syntax to generate HTML, making it concise and readable. When used with Express.js, Pug can render HTML on the server, allowing for flexible and customizable content based on data passed from the backend.
Install Express.js and Pug
To get started, ensure Node.js is installed. Then, create a new Express project and add the necessary dependencies:
npm init -y
npm install express pug
Configure Pug as the View Engine in Express
In your main server file (usually app.js
or server.js
), configure Express to use Pug as its templating engine:
const express = require('express');
const app = express();
// Set Pug as the templating engine
app.set('view engine', 'pug');
// Optional: Specify a custom directory for Pug views
app.set('views', __dirname + '/views');
Pug Project Structure
Here's an example of a complete Express project structure, including directories for Pug templates, reusable partials, and static assets:
express-pug-app/
├── views/
│ ├── partials/
│ │ ├── header.pug
│ │ └── footer.pug
│ └── pages/
│ ├── home.pug
│ ├── items.pug
│ └── products.pug
├── public/
│ ├── css/
│ ├── js/
│ └── images/
└── app.js
Create a Pug Template File
Inside the views/pages
directory, create a .pug
file to serve as your HTML template. Pug files use indentation rather than HTML tags, making them simpler to write and read.
//- views/pages/home.pug
doctype html
html(lang="en")
head
meta(charset="UTF-8")
meta(name="viewport", content="width=device-width, initial-scale=1.0")
title= title
body
h1= message
p This is a dynamic page rendered with Pug and Express.js.
In this example, title and message are dynamic values that will be passed from the server to the template.
Understanding Pug Syntax
Pug uses a minimal syntax, making it easy to write dynamic HTML. Here are a few essential rules:
- Plain Text: Lines without tags or variables are rendered as plain text.
p This is a paragraph in Pug.
- Dynamic Variables: Use
=
after a tag to insert dynamic content passed from Express.h1= title // Outputs the title variable
- HTML Attributes: Define attributes within parentheses after a tag. Multiple attributes are separated by spaces.
a(href="/contact" class="nav-link") Contact Us
- Interpolation: Use
#{}
within text to embed variables or expressions.p Welcome, #{user.name}!
- Conditionals: Use
if
,else if
, andelse
for conditional rendering.if user p Welcome, #{user.name}! else p Please log in to continue.
- Loops: Use
each
to loop through arrays and render a list or series of elements.ul each item in items li= item
Note: Proper indentation is crucial in Pug, as it defines the structure of your HTML. Consistent indentation ensures that nested elements are rendered correctly.
Passing Data from Express to Pug
Use res.render()
in Express to send data to your Pug template. The data is passed as an object and can be accessed in Pug using the variable names directly:
// Define a route
app.get('/', (req, res) => {
res.render('pages/home', { title: 'Welcome', message: 'Dynamic content with Pug and Express!' });
});
Using JavaScript Logic in Pug
Pug allows you to embed JavaScript logic, such as loops and conditionals, directly in your templates. This makes it simple to display lists, handle conditions, and create dynamic content.
// Route to render a list of items (example route)
app.get('/items', (req, res) => {
const items = ['Laptop', 'Smartphone', 'Tablet'];
res.render('pages/items', { items });
});
In the items.pug
file:
//- views/pages/items.pug
doctype html
html(lang="en")
head
meta(charset="UTF-8")
meta(name="viewport", content="width=device-width, initial-scale=1.0")
title Items List
body
h1 Items:
ul
each item in items
li= item
Including Partials
Pug makes it easy to reuse code by allowing you to include "partials" — separate template files for reusable components like headers, footers, or navigation bars. This helps keep your code clean and manageable, especially for larger applications.
Creating Partials
To make the header and footer reusable, create two separate .pug
files in a partials
directory under views
.
Header Partial (header.pug
):
//- views/partials/header.pug
header
nav
a(href="/") Home
a(href="/about") About Us
Footer Partial (footer.pug
):
//- views/partials/footer.pug
footer
p © 2024 Your Company
Using Partials in Main Templates
To include a partial in a main Pug template, use the include
keyword:
//- views/pages/home.pug
doctype html
html(lang="en")
head
meta(charset="UTF-8")
meta(name="viewport", content="width=device-width, initial-scale=1.0")
title= title
body
include ../partials/header
h1 Main Content
p Welcome to our dynamic page rendered with Pug and Express.js.
include ../partials/footer
With this setup, the header.pug
and footer.pug
partials are loaded automatically into any page that includes them, keeping your templates organized and your code more maintainable.
Complete Example
Let's bring everything together with a full example that includes routes, templates, and partials to create a simple product catalog. This example demonstrates how to structure your code, use partials, and pass data from Express to Pug.
Setting Up app.js
Start by creating an Express server in app.js
. Here, we'll set up Pug as the templating engine, define sample data, and create a route to display a list of products.
const express = require('express');
const app = express();
// Set up Pug as the templating engine
app.set('view engine', 'pug');
// Route to render the home page
app.get('/', (req, res) => {
res.render('pages/home', { title: 'Welcome', message: 'Dynamic content with Pug and Express!' });
});
// Route to render a list of items (example route)
app.get('/items', (req, res) => {
const items = ['Laptop', 'Smartphone', 'Tablet'];
res.render('pages/items', { items });
});
// Sample product data for product catalog
const products = [
{ id: 1, name: 'Laptop', price: 75000 },
{ id: 2, name: 'Smartphone', price: 50000 },
{ id: 3, name: 'Tablet', price: 35000 }
];
// Route to render the products page
app.get('/products', (req, res) => {
res.render('pages/products', {
title: 'Product Catalog',
products: products
});
});
// Start the server on port 3000
app.listen(3000, () => {
console.log('Server running on http://localhost:3000');
});
Creating the products.pug
Template
In the views/pages
directory, create a products.pug
file to display the product catalog. Use partials for the header and footer to keep the template organized.
//- views/pages/products.pug
doctype html
html(lang="en")
head
meta(charset="UTF-8")
meta(name="viewport", content="width=device-width, initial-scale=1.0")
title= title
body
include ../partials/header
main
h1= title
.products
each product in products
.product
h2= product.name
p Price: ₹#{product.price}
include ../partials/footer
Conclusion
In this tutorial, you've learned how to set up and configure Pug as a templating engine in Express.js, create and render dynamic HTML pages, pass data from Express to Pug, and use JavaScript logic in Pug templates to handle loops, conditionals, and partials. With this knowledge, you can now build data-driven, server-side rendered applications with flexible and customizable content.