# How Hugo's Page Collection and Sorting System Works Internally: A Deep Dive into the Source Code

> Discover how Hugo's page collection and sorting system works internally. Learn about its global page map, predicate queries, caching, and stable sorting for efficient content management.

- Repository: [GoHugo.io/hugo](https://github.com/gohugoio/hugo)
- Tags: internals
- Published: 2026-02-28

---

**Hugo uses a global page map (tree-based storage) to index all content, queries it with predicates to build collections, caches results in a per-site `pageCache`, and sorts them using a stable closure-based sorter that respects ordinal, weight, date, and language-aware collation.**

Hugo's renowned build speed relies on sophisticated content organization algorithms. The `gohugoio/hugo` repository implements a multi-layered page collection and sorting system that combines tree-based storage, predicate filtering, and aggressive memoization to handle sites with thousands of pages efficiently.

## 1. The Global Page Map Architecture

### 1.1 The pageMap Structure

All content in Hugo resides in a `pageMap` defined in [[`hugolib/content_map_page.go`](https://github.com/gohugoio/hugo/blob/main/hugolib/content_map_page.go)](https://github.com/gohugoio/hugo/blob/master/hugolib/content_map_page.go#L84-L102). This structure maintains a **tree of `contentNode` objects** (`treePages` and `treeResources`) indexed by content-path keys (e.g., `"/blog/post1"`).

```go
type pageMap struct {
    // Main storage for all pages.
    *pageTrees                // treePages, treeResources, …
    pageReverseIndex *contentTreeReverseIndex // simple look‑ups by filename
    // … several dynacache partitions for memoised look‑ups
}

```

The tree structure enables efficient prefix searches, allowing Hugo to retrieve entire sections or subtrees without scanning the entire site.

### 1.2 Querying with Predicates

When templates request `.RegularPages`, Hugo invokes `Site.RegularPages()` in [[`hugolib/site.go`](https://github.com/gohugoio/hugo/blob/main/hugolib/site.go)](https://github.com/gohugoio/hugo/blob/master/hugolib/site.go#L48-L62). This method queries the page map using a predicate-based filter:

```go
// hugolib/site.go – RegularPages()
func (s *Site) RegularPages() page.Pages {
    s.CheckReady()
    return s.pageMap.getPagesInSection(
        pageMapQueryPagesInSection{
            pageMapQueryPagesBelowPath: pageMapQueryPagesBelowPath{
                Path:    "",
                KeyPart: "global",
                Include: pagePredicates.ShouldListGlobal.
                         And(pagePredicates.KindPage).BoolFunc(),
            },
            Recursive: true,
        },
    )
}

```

The `pagePredicates.KindPage` ensures only regular content pages are returned, while `ShouldListGlobal` respects front-matter settings like `draft` and `publishdate`. The query constructs a **cache key** via `pageMapQueryPagesInSection.Key()` and checks the `cachePages1/2` partitions before walking the tree.

## 2. The Sorting Engine

### 2.1 DefaultPageSort: The Canonical Ordering

Hugo's default sort order is defined by **`DefaultPageSort`** in [[`resources/page/pages_sort.go`](https://github.com/gohugoio/hugo/blob/main/resources/page/pages_sort.go)](https://github.com/gohugoio/hugo/blob/master/resources/page/pages_sort.go#L82-L87):

```go
// DefaultPageSort is the default sort func for pages in Hugo:
// Order by Ordinal, Weight, Date, LinkTitle and then full file path.
DefaultPageSort = func(p1, p2 Page) bool {
    // 1. Explicit ordinal set via front‑matter
    o1, o2 := getOrdinals(p1, p2)
    if o1 != o2 && o1 != -1 && o2 != -1 { return o1 < o2 }

    // 2. Weight0 (taxonomy weight)
    w01, w02 := getWeight0s(p1, p2)
    if w01 != w02 && w01 != -1 && w02 != -1 { return w01 < w02 }

    // 3. Date (newest first)
    if p1.Weight() == p2.Weight() {
        if p1.Date().Unix() == p2.Date().Unix() {
            // 4. LinkTitle (language‑aware collator)
            c := collatorStringCompare(func(p Page) string { return p.LinkTitle() }, p1, p2)
            if c == 0 {
                // 5. Full normalized file path as a final tiebreaker
                return compare.LessStrings(p1.PathInfo().Path(), p2.PathInfo().Path())
            }
            return c < 0
        }
        return p1.Date().Unix() > p2.Date().Unix()
    }
    // … weight fallback omitted for brevity …
}

```

This **stable sort** uses `sort.Stable` and implements a five-tier hierarchy: **ordinal** (explicit front-matter), **weight0** (taxonomy weight), **date** (descending), **link title** (language-aware collation), and **file path** (final tiebreaker).

### 2.2 Language-Aware Collation

When sorting by title or link title, Hugo uses `langs.GetCollator1` from [[`langs/collator.go`](https://github.com/gohugoio/hugo/blob/main/langs/collator.go)](https://github.com/gohugoio/hugo/blob/master/langs/collator.go) to ensure proper Unicode sorting according to the site's language settings. The `collatorStringCompare` function wraps this collator for use in the `DefaultPageSort` closure.

### 2.3 The pageCache (spc) for Memoization

To prevent redundant sorting operations, Hugo maintains a global **`pageCache`** instantiated as `spc` in [[`resources/page/pages_sort.go`](https://github.com/gohugoio/hugo/blob/main/resources/page/pages_sort.go)](https://github.com/gohugoio/hugo/blob/master/resources/page/pages_sort.go#L30):

```go
var spc = newPageCache() // pages_sort.go:30

```

The `newPageCache()` function (see [[`pages_cache.go`](https://github.com/gohugoio/hugo/blob/main/pages_cache.go)](https://github.com/gohugoio/hugo/blob/master/resources/page/pages_cache.go#L44-L52)) creates two dynacache partitions (`cachePages1` and `cachePages2`). When a sort method like `.ByTitle` is invoked, it calls `spc.get(key, sorter, pages)`, which either returns the cached slice or performs the sort, stores the result, and returns it. This makes repeated calls **O(1)** after the initial computation.

### 2.4 Shortcut Sort Methods

Convenience methods like **`ByTitle`**, **`ByWeight`**, and **`ByDate`** are thin wrappers around the same machinery. For example, **`ByTitle`** in [[`resources/page/pages_sort.go`](https://github.com/gohugoio/hugo/blob/main/resources/page/pages_sort.go)](https://github.com/gohugoio/hugo/blob/master/resources/page/pages_sort.go#L42-L53) builds a language-aware string sorter:

```go
func (p Pages) ByTitle() Pages {
    const key = "pageSort.ByTitle"
    pages, _ := spc.get(key,
        collatorStringSort(func(p Page) string { return p.Title() }), p)
    return pages
}

```

All sort methods share:
- A **`pageBy` closure** implementing comparison logic
- A **`pageSorter`** satisfying `sort.Interface`
- The **`spc` cache** for memoization

## 3. Practical Usage in Templates

### 3.1 Basic Page Collection

When you range over `.Site.RegularPages` in a template:

```go
{{ range .Site.RegularPages }}
  <a href="{{ .RelPermalink }}">{{ .Title }}</a><br>
{{ end }}

```

Behind the scenes, this triggers `Site.RegularPages()` → `pageMap.getPagesInSection` with the `KindPage` predicate. If no explicit sort is requested, Hugo applies `DefaultPageSort` to ensure consistent ordering.

### 3.2 Explicit Sorting by Title

To sort by title using language-aware collation:

```go
{{ $pages := .Site.RegularPages.ByTitle }}
{{ range $pages }}
  {{ .Title }} – {{ .RelPermalink }}
{{ end }}

```

This invokes `Pages.ByTitle()`, which uses `collatorStringSort` with `langs.GetCollator1` for proper Unicode handling, then caches the result in `spc`.

### 3.3 Custom Sorting with Sort Function

For ad-hoc sorting in templates:

```go
{{ $sorted := .Site.RegularPages.Sort "Date" "desc" }}
{{ range $sorted }}
  {{ .Date.Format "2006-01-02" }} – {{ .Title }}
{{ end }}

```

The `ns.Sort` method (see [[`tpl/collections/sort.go`](https://github.com/gohugoio/hugo/blob/main/tpl/collections/sort.go)](https://github.com/gohugoio/hugo/blob/master/tpl/collections/sort.go#L30-L56)) constructs a `pageBy` closure from the arguments and delegates to the `pageSorter` logic, maintaining consistency with the built-in sort methods.

## 4. Key Source Files Reference

| Area | File | Description |
|------|------|-------------|
| Page map & query | [[`hugolib/content_map_page.go`](https://github.com/gohugoio/hugo/blob/main/hugolib/content_map_page.go)](https://github.com/gohugoio/hugo/blob/master/hugolib/content_map_page.go) | `pageMap`, tree structures, cache partitions, query predicates |
| Site API | [[`hugolib/site.go`](https://github.com/gohugoio/hugo/blob/main/hugolib/site.go)](https://github.com/gohugoio/hugo/blob/master/hugolib/site.go) | `Site.RegularPages()` implementation |
| Page collection interface | [[`resources/page/page.go`](https://github.com/gohugoio/hugo/blob/main/resources/page/page.go)](https://github.com/gohugoio/hugo/blob/master/resources/page/page.go) | `Page` interface and `Pages` type definition |
| Default sort function | [[`resources/page/pages_sort.go`](https://github.com/gohugoio/hugo/blob/main/resources/page/pages_sort.go)](https://github.com/gohugoio/hugo/blob/master/resources/page/pages_sort.go) | `DefaultPageSort` definition and sort helpers |
| Sort cache | [[`resources/page/pages_cache.go`](https://github.com/gohugoio/hugo/blob/main/resources/page/pages_cache.go)](https://github.com/gohugoio/hugo/blob/master/resources/page/pages_cache.go) | `pageCache` implementation (`spc`) |
| Collection template functions | [[`tpl/collections/sort.go`](https://github.com/gohugoio/hugo/blob/main/tpl/collections/sort.go)](https://github.com/gohugoio/hugo/blob/master/tpl/collections/sort.go) | Public `.Sort` method for templates |
| Language collator | [[`langs/collator.go`](https://github.com/gohugoio/hugo/blob/main/langs/collator.go)](https://github.com/gohugoio/hugo/blob/master/langs/collator.go) | `GetCollator1` for Unicode-aware sorting |

## Summary

- **Tree-based storage**: Hugo stores all content in a `pageMap` (defined in [`hugolib/content_map_page.go`](https://github.com/gohugoio/hugo/blob/main/hugolib/content_map_page.go)) using path-indexed trees for efficient subtree queries.
- **Predicate filtering**: Collections like `.RegularPages` are built by querying the map with boolean predicates (e.g., `pagePredicates.KindPage`) that respect draft status and publication dates.
- **Hierarchical sorting**: The `DefaultPageSort` function implements a five-tier sort order: ordinal, weight0, date (descending), link title (language-aware), and file path.
- **Memoization**: Both collection queries and sort operations are cached using the `pageCache` (`spc`) to ensure O(1) retrieval on subsequent template calls during the same build.
- **Language awareness**: Sorting uses `langs.GetCollator1` to ensure proper Unicode collation according to site language settings.

## Frequently Asked Questions

### How does Hugo cache page collections to improve build performance?

Hugo implements a two-level caching strategy. First, the `pageMap` queries use cache partitions (`cachePages1` and `cachePages2`) to store filtered collections like `.RegularPages`. Second, the `pageCache` (variable `spc` in [`resources/page/pages_sort.go`](https://github.com/gohugoio/hugo/blob/main/resources/page/pages_sort.go)) memoizes sorted slices. When a template calls `.ByTitle` or `.ByWeight` multiple times, Hugo returns the cached result after the first computation, making subsequent calls O(1).

### What is the difference between .Pages and .RegularPages in Hugo's internal system?

Internally, `.Pages` typically returns all pages in a section including nested sections and taxonomy pages, while `.RegularPages` (implemented in [`hugolib/site.go`](https://github.com/gohugoio/hugo/blob/main/hugolib/site.go)) specifically filters for content pages of kind `Page` using the predicate `pagePredicates.KindPage.And(pagePredicates.ShouldListGlobal)`. This ensures `.RegularPages` excludes section listings, taxonomy terms, and draft content unless explicitly configured otherwise.

### How does Hugo handle sorting for multilingual sites with different character sets?

Hugo uses the `langs.GetCollator1` function from [`langs/collator.go`](https://github.com/gohugoio/hugo/blob/main/langs/collator.go) to create language-specific collators. When sorting by title or link title (as seen in `DefaultPageSort` and the `ByTitle` method), Hugo passes the strings through `collatorStringCompare`, which uses the appropriate Unicode collation rules for the site's language. This ensures that accented characters and non-Latin scripts sort correctly according to locale-specific rules rather than simple byte comparison.

### Why does Hugo use a stable sort for page collections?

Hugo uses `sort.Stable` (via the `pageSorter` implementation) to preserve the relative order of pages that compare as equal. This is critical because `DefaultPageSort` uses a five-tier fallback system (ordinal → weight0 → date → link title → path). Without stable sorting, pages with identical weights and dates could shuffle randomly between builds, causing non-deterministic output. Stability ensures reproducible builds and consistent pagination across site regenerations.