Introduction to Pug
Think of Pug as a translator between two languages - it takes simple, readable code and converts it into the HTML that browsers understand. Just as you might use shorthand when taking notes, Pug lets you write HTML in a more concise way. Imagine writing a letter - HTML would be like writing it in formal language with all the proper salutations and closings, while Pug is like writing quick notes that get automatically formatted into proper letters.
Why Use Pug?
In the world of web development, Pug serves as your efficient assistant, similar to how a smart email client might autocomplete your sentences or format your text. When building websites, especially larger ones, writing raw HTML can become repetitive and error-prone - like writing the same letter hundreds of times by hand. Pug automates this process, ensuring consistency and reducing mistakes, just as a template would help you write consistent business letters.
Basic Syntax
Let's explore Pug's syntax through a simple analogy. If HTML is like writing detailed directions with full sentences ("Turn right at the intersection, then go straight for two blocks"), Pug is like giving the same directions in shorthand ("R @ int, 2 blks str"). Both convey the same information, but Pug is more concise.
// HTML version
<div class="container">
<h1 class="title">Welcome</h1>
<p class="content">Hello, World!</p>
</div>
// Pug version
div.container
h1.title Welcome
p.content Hello, World!
Working with Variables
Pug's variable system works like a restaurant menu where the kitchen (server) provides the ingredients (data), and the menu (template) displays them in an organized way. Here's a practical example:
// Server-side code (Express.js)
app.get('/', (req, res) => {
res.render('index', {
username: 'Sarah',
items: ['Apple', 'Banana', 'Orange']
});
});
// Pug template (index.pug)
div.welcome
h1 Hello #{username}!
ul
each item in items
li= item
Template Inheritance
Think of template inheritance like building with LEGO blocks. You have a base template (the foundation piece) and multiple child templates (specialized pieces that snap onto the base). This is particularly useful for maintaining consistent layouts across your website, just like how every page in a book has the same header and footer.
// layout.pug (Base template)
html
head
title #{pageTitle} - My Site
body
header
nav
// Navigation items
block content
footer
p © 2025 My Website
// page.pug (Child template)
extends layout
block content
h1 Welcome to our site
p This is the main content
Mixins - Reusable Components
Mixins in Pug are like recipe cards in a cookbook. Once you write a recipe (mixin), you can use it multiple times with different ingredients (parameters). This is especially useful for components that appear frequently on your site, like product cards or user profiles.
// Define a mixin for a product card
mixin productCard(title, price, description)
div.card
h3= title
p.price $#{price}
p.description= description
button.buy Buy Now
// Use the mixin
+productCard('Coffee Maker', 49.99, 'Premium coffee maker')
+productCard('Toaster', 29.99, 'Two-slice toaster')
Real-World Application
Let's look at a practical example of building an e-commerce product listing page:
// products.pug
extends layout
block content
section.products
h1 Our Products
.filters
select#category
option(value='') All Categories
each category in categories
option(value=category.id)= category.name
.product-grid
each product in products
+productCard(product)
mixin productCard(product)
.product-card
img(src=product.image alt=product.name)
h3= product.name
p.price $#{product.price}
if product.inStock
button.add-to-cart Add to Cart
else
button.out-of-stock(disabled) Out of Stock
Common Patterns and Best Practices
When working with Pug in real projects, consider these patterns that experienced developers use:
Organize your templates like a well-structured document library:
views/
layouts/
main.pug
admin.pug
partials/
header.pug
footer.pug
components/
product-card.pug
user-profile.pug
pages/
home.pug
products.pug
Advanced Features
Pug offers several advanced features that can make your templates more powerful and maintainable:
// Conditional Classes
div(class={
active: isActive,
'text-bold': shouldBeBold,
hidden: !isVisible
})
// Iteration with Object Properties
each val, key in objects
p #{key}: #{val}
// Template Filters
script
:babel
const x = () => console.log('Hello');
style
:scss
$color: blue;
.box { color: $color; }
Performance Considerations
Just as a restaurant kitchen prepares ingredients before service begins, Pug templates are compiled into functions that can quickly generate HTML. This compilation happens once when your application starts, making subsequent renders very fast.
Debugging Tips
When working with Pug, debugging is like being a detective. Here are some common issues and their solutions:
// Problem: Undefined variable
h1= title // Error if 'title' is not passed to template
// Solution: Use conditional or default value
h1= title || 'Default Title'
// Problem: Incorrect indentation
div
p This works
p This breaks // Wrong indentation
// Solution: Consistent indentation
div
p This works
p This also works
Further Learning
To deepen your understanding of Pug, explore these related topics:
- Express.js integration and middleware
- Template caching strategies
- Custom Pug filters
- Integration with CSS preprocessors
- Build tools and compilation options