Reusing Layouts with Pug Template Inheritance
Learn how Pug’s extends and block keywords let you define a reusable layout and inject page‑specific content, reducing duplication in Node.js/Express apps.
10 Nov 2025, 21:14 UTC

The problem: duplicated markup across pages
When building a Node.js web app with Express, it’s common to repeat the same HTML skeleton—<head>, navigation, footer—on every view. Copy‑pasting this boilerplate makes updates error‑prone and clutters the repository.
Thesis: Pug’s extends and block keywords let you define a single layout and inject page‑specific content without duplication.
How template inheritance works
Pug treats a template that uses extends as a child that fills in placeholders defined by block in a parent layout. If the child does not override a block, the parent’s default markup is rendered, providing a fallback.
extends– specifies the path to the base layout file (relative or absolute).block– marks a region in the parent that can be replaced; optional default content can be placed inside the block.- Resolution happens at render time: Pug walks the inheritance chain, merges blocks, and produces the final HTML.
Worked example: a simple blog layout
Assume you have an Express app with Pug set as the view engine (app.set('view engine', 'pug');).
1. Create the base layout (layout.pug)
doctype html
html
head
title My Blog
block head
//‑ default head content (can be overridden)
body
header
h1 My Blog
main
block content
//‑ default content shown when child does not override
footer
small © 2026 My Blog
This file defines two blocks: head (with default empty content) and content (also empty by default).
2. Create a child view (index.pug)
extends layout
block head
meta(name='description' content='Home page')
block content
article
h2 Welcome
p This is the home page.
The child inherits layout.pug, replaces the head block with a meta tag, and supplies its own markup for content.
3. Render the view
Via the Pug CLI (useful for quick checks):
# Run from the project root where the .pug files live
# No special permissions needed beyond read access to the files
pug -P index.pug
Or through Express in a route handler:
app.get('/', (req, res) => {
res.render('index'); // Express looks for views/index.pug
});
After rendering, inspect the generated HTML. You should see the <title> from the layout, the meta tag inserted by the child’s head block, and the article markup inside the <main> element, surrounded by the header and footer from the layout.
4. Verify fallback behavior
Remove the block content section from index.pug and re‑render. The output will now show the default (empty) content from the layout’s content block, proving that omitted overrides fall back to the parent’s definition.
Trade‑offs and limitations
While inheritance reduces duplication, it introduces considerations:
- Depth of chains: Deeply nested
extendsrelationships can make it hard to trace where a particular block originates, especially when multiple intermediate layouts define defaults. - Circular extends: If a template (directly or indirectly) extends itself, Pug throws a runtime error. Keeping a flat inheritance graph avoids this.
- Overriding defaults: Accidentally leaving a block empty in a child can produce unexpected blank sections; always verify that required blocks are supplied.
Practical check: after any change to a layout, run the CLI on a representative child view and diff the output against a known‑good baseline. This catches missing overrides or unintended side effects without needing a full browser test.
Actionable closing
Start by extracting the repeated HTML skeleton of your app into a single layout.pug file. Identify the sections that vary per page—typically title, meta tags, and main content—and turn them into block definitions. Then refactor each view to extends layout and override only the blocks it needs. Keep the inheritance depth to two or three levels unless you have a clear reason to go deeper, and periodically run the Pug CLI on your views to ensure the generated HTML matches expectations. This approach gives you a maintainable, DRY template base while retaining full control over page‑specific markup.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.