Understanding Pug Templates

A Comprehensive Guide for Web Developers

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: