Control Flow Guide

Last updated: October 6, 2025

Control Flow Guide

Master conditional logic and loops in your document templates for dynamic content generation.

Table of Contents

if/else/end - Conditional Rendering

Basic if Statement

Render content only when a condition is true:

{{if .IsPaid}}
<span class="badge badge-success">PAID</span>
{{end}}

Sample Data:

{
  "IsPaid": true
}

Output:

<span class="badge badge-success">PAID</span>

if/else Statement

Choose between two alternatives:

{{if .IsActive}}
<span class="status-active">Active</span>
{{else}}
<span class="status-inactive">Inactive</span>
{{end}}

Sample Data:

{
  "IsActive": false
}

Output:

<span class="status-inactive">Inactive</span>

if/else if/else Chain

Multiple conditions:

{{if eq .Status "completed"}}
<span class="badge-success">✓ Completed</span>
{{else if eq .Status "pending"}}
<span class="badge-warning">⏱ Pending</span>
{{else if eq .Status "cancelled"}}
<span class="badge-danger">✗ Cancelled</span>
{{else}}
<span class="badge-info">• Unknown</span>
{{end}}

Sample Data:

{
  "Status": "pending"
}

Output:

<span class="badge-warning">⏱ Pending</span>

Checking for Empty/Nil Values

{{if .Email}}
<p>Contact: {{.Email}}</p>
{{else}}
<p>No contact email provided</p>
{{end}}

{{if .Items}}
<p>{{len .Items}} items in cart</p>
{{else}}
<p>Cart is empty</p>
{{end}}

Negation with not

{{if not .IsDeleted}}
<div class="active-record">
  <p>{{.Name}}</p>
</div>
{{end}}

range/end - Looping

Simple Array Iteration

Loop through array elements:

<ul>
{{range .Tags}}
  <li>{{.}}</li>
{{end}}
</ul>

Sample Data:

{
  "Tags": ["urgent", "important", "review"]
}

Output:

<ul>
  <li>urgent</li>
  <li>important</li>
  <li>review</li>
</ul>

Iterating Objects in Array

<table>
  <thead>
    <tr>
      <th>Product</th>
      <th>Price</th>
      <th>Quantity</th>
    </tr>
  </thead>
  <tbody>
    {{range .Products}}
    <tr>
      <td>{{.Name}}</td>
      <td>${{.Price}}</td>
      <td>{{.Quantity}}</td>
    </tr>
    {{end}}
  </tbody>
</table>

Sample Data:

{
  "Products": [
    {"Name": "Widget", "Price": 19.99, "Quantity": 5},
    {"Name": "Gadget", "Price": 29.99, "Quantity": 3}
  ]
}

range with Index

Capture both index and value:

{{range $index, $item := .Items}}
<div class="item-{{$index}}">
  <p>Item #{{$index}}: {{$item.Name}}</p>
</div>
{{end}}

Sample Data:

{
  "Items": [
    {"Name": "First Item"},
    {"Name": "Second Item"}
  ]
}

Output:

<div class="item-0">
  <p>Item #0: First Item</p>
</div>
<div class="item-1">
  <p>Item #1: Second Item</p>
</div>

range with else

Handle empty arrays:

<ul>
{{range .Notifications}}
  <li>{{.Message}}</li>
{{else}}
  <li>No notifications</li>
{{end}}
</ul>

Sample Data (empty):

{
  "Notifications": []
}

Output:

<ul>
  <li>No notifications</li>
</ul>

Nested range Loops

{{range .Categories}}
<div class="category">
  <h3>{{.Name}}</h3>
  <ul>
    {{range .Products}}
    <li>{{.Name}} - ${{.Price}}</li>
    {{end}}
  </ul>
</div>
{{end}}

Sample Data:

{
  "Categories": [
    {
      "Name": "Electronics",
      "Products": [
        {"Name": "Laptop", "Price": 999},
        {"Name": "Mouse", "Price": 25}
      ]
    },
    {
      "Name": "Books",
      "Products": [
        {"Name": "Go Programming", "Price": 45}
      ]
    }
  ]
}

with/end - Context Setting

Basic with Statement

Set context for nested object access:

{{with .Customer}}
<div class="customer">
  <h2>{{.Name}}</h2>
  <p>{{.Email}}</p>
  <p>{{.Phone}}</p>
</div>
{{end}}

Sample Data:

{
  "Customer": {
    "Name": "John Doe",
    "Email": "john@example.com",
    "Phone": "+1-555-1234"
  }
}

Output:

<div class="customer">
  <h2>John Doe</h2>
  <p>john@example.com</p>
  <p>+1-555-1234</p>
</div>

with/else

Handle missing nested objects:

{{with .BillingAddress}}
<div class="billing">
  <p>{{.Street}}</p>
  <p>{{.City}}, {{.State}}</p>
</div>
{{else}}
<p>No billing address on file</p>
{{end}}

Accessing Parent Context in with

Use $ to access root context:

{{with .Order}}
<div class="order">
  <p>Order: {{.Number}}</p>
  <p>Company: {{$.CompanyName}}</p>
  <p>Customer: {{.CustomerName}}</p>
</div>
{{end}}

Sample Data:

{
  "CompanyName": "Acme Corp",
  "Order": {
    "Number": "ORD-001",
    "CustomerName": "John Doe"
  }
}

Output:

<div class="order">
  <p>Order: ORD-001</p>
  <p>Company: Acme Corp</p>
  <p>Customer: John Doe</p>
</div>

Comparison Operators

eq - Equal

{{if eq .Status "active"}}
<span class="active">Active</span>
{{end}}

{{if eq .Count 0}}
<p>No items</p>
{{end}}

ne - Not Equal

{{if ne .Status "deleted"}}
<div class="record">{{.Name}}</div>
{{end}}

lt - Less Than

{{if lt .Stock 10}}
<span class="low-stock">Low Stock!</span>
{{end}}

le - Less Than or Equal

{{if le .Score 60}}
<span class="fail">Failed</span>
{{end}}

gt - Greater Than

{{if gt .Price 1000}}
<span class="premium">Premium Item</span>
{{end}}

ge - Greater Than or Equal

{{if ge .Age 18}}
<p>Adult</p>
{{end}}

Comparison Examples

<!-- Multiple comparisons -->
{{if and (ge .Price 100) (le .Price 500)}}
<span class="mid-range">Mid-range product</span>
{{end}}

{{if or (eq .Type "urgent") (eq .Type "critical")}}
<span class="alert">High Priority!</span>
{{end}}

Logical Operators

and - Logical AND

All conditions must be true:

{{if and .IsActive .IsPaid}}
<span class="status-good">Active & Paid</span>
{{end}}

{{if and (gt .Stock 0) (le .Stock 10)}}
<span class="low-stock">Running low</span>
{{end}}

or - Logical OR

At least one condition must be true:

{{if or .IsAdmin .IsModerator}}
<button>Edit</button>
{{end}}

{{if or (eq .Status "pending") (eq .Status "processing")}}
<span class="in-progress">In Progress</span>
{{end}}

not - Logical NOT

Negate a condition:

{{if not .IsDeleted}}
<div class="active-item">{{.Name}}</div>
{{end}}

{{if not (eq .Status "archived")}}
<button>Archive</button>
{{end}}

Complex Conditions

{{if and (not .IsDeleted) (or .IsActive .IsPending)}}
<div class="available-item">
  <p>{{.Name}}</p>
</div>
{{end}}

Real-World Examples

Example 1: Invoice with Conditional Sections

<div class="invoice">
  <h1>Invoice #{{.InvoiceNumber}}</h1>
  
  <!-- Payment status -->
  {{if .IsPaid}}
  <div class="paid-stamp">
    <p>PAID</p>
    <p>Paid on: {{.PaidDate | dateFormat "Jan 2, 2006"}}</p>
  </div>
  {{else}}
  <div class="unpaid-notice">
    <p>Payment Due: {{.DueDate | dateFormat "Jan 2, 2006"}}</p>
    {{if .IsOverdue}}
    <p class="overdue">OVERDUE</p>
    {{end}}
  </div>
  {{end}}
  
  <!-- Line items -->
  <table>
    {{range .Items}}
    <tr>
      <td>{{.Description}}</td>
      <td>{{.Quantity}}</td>
      <td>${{.Price | printf "%.2f"}}</td>
      <td>${{.Total | printf "%.2f"}}</td>
      {{if .IsDiscounted}}
      <td class="discount">-{{.DiscountPercent}}%</td>
      {{end}}
    </tr>
    {{end}}
  </table>
  
  <!-- Totals -->
  <div class="totals">
    <p>Subtotal: ${{.Subtotal | printf "%.2f"}}</p>
    {{if gt .DiscountAmount 0}}
    <p>Discount: -${{.DiscountAmount | printf "%.2f"}}</p>
    {{end}}
    {{if gt .Tax 0}}
    <p>Tax ({{.TaxRate}}%): ${{.Tax | printf "%.2f"}}</p>
    {{end}}
    <p class="total">Total: ${{.Total | printf "%.2f"}}</p>
  </div>
  
  <!-- Notes -->
  {{with .Notes}}
  <div class="notes">
    <h3>Notes</h3>
    <p>{{.}}</p>
  </div>
  {{end}}
</div>

Example 2: Order Status Tracker

<div class="order-tracker">
  <h2>Order #{{.OrderNumber}}</h2>
  
  <div class="status-timeline">
    <!-- Order Placed -->
    <div class="step {{if .OrderPlaced}}completed{{end}}">
      <span class="icon">✓</span>
      <p>Order Placed</p>
      {{if .OrderPlaced}}
      <p class="date">{{.PlacedDate | dateFormat "Jan 2, 3:04 PM"}}</p>
      {{end}}
    </div>
    
    <!-- Processing -->
    <div class="step {{if .IsProcessing}}active{{else if .Processed}}completed{{end}}">
      <span class="icon">{{if .Processed}}✓{{else}}⏱{{end}}</span>
      <p>Processing</p>
      {{if .Processed}}
      <p class="date">{{.ProcessedDate | dateFormat "Jan 2, 3:04 PM"}}</p>
      {{end}}
    </div>
    
    <!-- Shipped -->
    <div class="step {{if .IsShipping}}active{{else if .Shipped}}completed{{end}}">
      <span class="icon">{{if .Shipped}}✓{{else}}📦{{end}}</span>
      <p>Shipped</p>
      {{if .Shipped}}
      <p class="date">{{.ShippedDate | dateFormat "Jan 2, 3:04 PM"}}</p>
      <p class="tracking">Tracking: {{.TrackingNumber}}</p>
      {{end}}
    </div>
    
    <!-- Delivered -->
    <div class="step {{if .Delivered}}completed{{end}}">
      <span class="icon">{{if .Delivered}}✓{{else}}🏠{{end}}</span>
      <p>Delivered</p>
      {{if .Delivered}}
      <p class="date">{{.DeliveredDate | dateFormat "Jan 2, 3:04 PM"}}</p>
      {{end}}
    </div>
  </div>
  
  <!-- Cancellation notice -->
  {{if .IsCancelled}}
  <div class="cancelled-notice">
    <p>This order was cancelled on {{.CancelledDate | dateFormat "Jan 2, 2006"}}</p>
    {{with .CancellationReason}}
    <p>Reason: {{.}}</p>
    {{end}}
  </div>
  {{end}}
</div>

Example 3: Product Listing with Filters

<div class="product-listing">
  <h1>{{.CategoryName}}</h1>
  
  {{range .Products}}
  {{if not .IsDiscontinued}}
  <div class="product">
    <h3>{{.Name}}</h3>
    
    <!-- Price display -->
    {{if .OnSale}}
    <p class="price">
      <span class="original">${{.OriginalPrice | printf "%.2f"}}</span>
      <span class="sale">${{.SalePrice | printf "%.2f"}}</span>
      <span class="savings">Save {{.SavingsPercent}}%</span>
    </p>
    {{else}}
    <p class="price">${{.Price | printf "%.2f"}}</p>
    {{end}}
    
    <!-- Stock status -->
    {{if eq .Stock 0}}
    <p class="out-of-stock">Out of Stock</p>
    {{else if lt .Stock 5}}
    <p class="low-stock">Only {{.Stock}} left!</p>
    {{else if le .Stock 20}}
    <p class="limited-stock">{{.Stock}} available</p>
    {{else}}
    <p class="in-stock">In Stock</p>
    {{end}}
    
    <!-- Features -->
    {{if .Features}}
    <ul class="features">
      {{range .Features}}
      <li>{{.}}</li>
      {{end}}
    </ul>
    {{end}}
    
    <!-- Ratings -->
    {{if and .Rating (gt .Rating 0)}}
    <div class="rating">
      <span class="stars">{{.Rating}} ★</span>
      {{if .ReviewCount}}
      <span class="reviews">({{.ReviewCount}} reviews)</span>
      {{end}}
    </div>
    {{end}}
    
    <!-- Badges -->
    <div class="badges">
      {{if .IsNew}}
      <span class="badge-new">NEW</span>
      {{end}}
      {{if .IsBestseller}}
      <span class="badge-bestseller">BESTSELLER</span>
      {{end}}
      {{if .IsFeatured}}
      <span class="badge-featured">FEATURED</span>
      {{end}}
    </div>
  </div>
  {{end}}
  {{else}}
  <p class="no-products">No products available in this category.</p>
  {{end}}
</div>

Example 4: Conditional Report Sections

<div class="report">
  <h1>{{.ReportTitle}}</h1>
  <p class="period">Period: {{.StartDate | dateFormat "Jan 2"}} - {{.EndDate | dateFormat "Jan 2, 2006"}}</p>
  
  <!-- Executive Summary (always shown) -->
  <section class="summary">
    <h2>Executive Summary</h2>
    <p>{{.Summary}}</p>
  </section>
  
  <!-- Sales Data (only if available) -->
  {{with .SalesData}}
  <section class="sales">
    <h2>Sales Performance</h2>
    <p>Total Revenue: ${{.TotalRevenue | printf "%.2f"}}</p>
    
    {{if gt .GrowthRate 0}}
    <p class="positive">Growth: +{{.GrowthRate}}%</p>
    {{else if lt .GrowthRate 0}}
    <p class="negative">Decline: {{.GrowthRate}}%</p>
    {{else}}
    <p>No change from previous period</p>
    {{end}}
    
    {{if .TopProducts}}
    <h3>Top Products</h3>
    <ol>
      {{range .TopProducts}}
      <li>{{.Name}} - ${{.Revenue | printf "%.2f"}}</li>
      {{end}}
    </ol>
    {{end}}
  </section>
  {{end}}
  
  <!-- Customer Data (only if requested) -->
  {{if .IncludeCustomerData}}
  {{with .CustomerData}}
  <section class="customers">
    <h2>Customer Insights</h2>
    <p>New Customers: {{.NewCustomers}}</p>
    <p>Returning Customers: {{.ReturningCustomers}}</p>
    
    {{if .ChurnRate}}
    {{if gt .ChurnRate 10}}
    <p class="warning">High churn rate: {{.ChurnRate}}%</p>
    {{else}}
    <p>Churn rate: {{.ChurnRate}}%</p>
    {{end}}
    {{end}}
  </section>
  {{end}}
  {{end}}
  
  <!-- Recommendations (conditional) -->
  {{if and .Recommendations (gt (len .Recommendations) 0)}}
  <section class="recommendations">
    <h2>Recommendations</h2>
    <ul>
      {{range .Recommendations}}
      <li class="priority-{{.Priority}}">{{.Text}}</li>
      {{end}}
    </ul>
  </section>
  {{end}}
</div>

Best Practices

  1. Keep Logic Simple: Move complex logic to your application, not templates
  2. Use with for Nested Objects: Makes templates cleaner and easier to read
  3. Handle Empty Cases: Always provide else branches for better user experience
  4. Save Root Context: Use $root := . when nesting to access parent data
  5. Validate Data: Check for nil/empty before accessing nested properties
  6. Use range/else: Handle empty arrays gracefully
  7. Comment Complex Logic: Use {{/* comments */}} to explain conditions

Common Patterns

Pattern 1: Show/Hide Sections

{{if .ShowSection}}
<section>Content here</section>
{{end}}

Pattern 2: Alternative Content

{{if .HasData}}
<div>{{.Data}}</div>
{{else}}
<div>No data available</div>
{{end}}

Pattern 3: Status-Based Styling

<div class="item status-{{.Status | lower}}">
  {{if eq .Status "active"}}
  <!-- Active content -->
  {{else}}
  <!-- Inactive content -->
  {{end}}
</div>

Pattern 4: Conditional Formatting

{{if gt .Amount 1000}}
<span class="high-value">${{.Amount}}</span>
{{else}}
<span>${{.Amount}}</span>
{{end}}

Next Steps

Pro Tip: Test all conditional branches with different sample data to ensure your template handles all cases correctly!

Was this page helpful?