Building Tag‑Based Archive Pages in Hugo with Native Pagination
Learn how to use Hugo’s native taxonomies and .Paginator to create fast, paginated tag archive pages without extra plugins.
06 Aug 2026, 01:51 UTC

Problem: You want tag‑based archive pages without extra plugins
When a Hugo site grows, readers often need a way to browse all posts that share a tag. Manually creating those pages is tedious and error‑prone. Hugo already generates taxonomy pages for any front‑matter list, but you still need to add pagination so large tag lists stay usable.
Thesis: Hugo’s built‑in taxonomies and .Paginator give you zero‑setup tag archives that are fast to rebuild and easy to style.
1. Enable the tag taxonomy
Add (or confirm) a taxonomies section in your site config. If you are using the default config.yaml, the snippet below is enough:
# config.yaml
taxonomies:
tag: tags
Run this from the site root (you need write permission to the config file):
# No special privileges required; just edit the file with your editor.
Risk: If you already have a taxonomies block, merging incorrectly can break other taxonomies. Verify by running hugo server and checking that /tags/ appears in the URL bar after you create a post with a tag.
2. Add tags to your content
In any markdown post under content/posts/, include a tags list in the front matter:
---
title: "My first Go post"
date: 2026-09-01
tags:
- go
- hugo
---
# Post content here
Create a couple of posts with overlapping tags so you can see pagination later.
3. Create a tag template that paginates
Hugo looks for layouts/tag/terms.html (or layouts/_default/terms.html) to render taxonomy pages. Add the following file:
# layouts/tag/terms.html
{{ define "main" }}
Posts tagged "{{ .Title }}"
{{ if .Paginator }}
{{ $pages := .Paginator.Pages }}
{{ else }}
{{ $pages := .Pages }}
{{ end }}
{{ range $pages }}
- {{ .Title }}
{{ end }}
{{ if .Paginator }}
{{ if .Paginator.Prev }}
« Prev
{{ end }}
Page {{ .Paginator.PageNumber }} of {{ .Paginator.TotalPages }}
{{ if .Paginator.Next }}
Next »
{{ end }}
{{ end }}
{{ end }}
Place this file in your site’s layouts/ directory (write permission required). No extra dependencies are needed.
4. Worked example: seeing pagination in action
- From an empty directory, run:
hugo new site tag-demo
cd tag-demo
# copy the config.yaml snippet above into config.yaml
mkdir -p content/posts
# create 7 posts tagged "go"
for i in {1..7}; do
hugo new posts/go-post-$i.md
sed -i "s/title: .*/title: \"Go post $i\"/; s/tags:.*/tags:\n - go/" content/posts/go-post-$i.md
done
Now start the server:
hugo server -D
Visit http://localhost:1313/tags/go/. You should see a list of posts with pagination controls at the bottom (because the default paginate size is 10; you can lower it to see multiple pages).
To verify the generated file, stop the server and inspect:
cat public/tags/go/index.html
You will find markup similar to the template above, with <a> elements for prev/next links when applicable.
5. Performance considerations
Hugo builds all tag pages during the single site generation pass. Incremental builds only regenerate the tag pages whose associated posts changed. On a test site with 5,000 posts and 200 tags, a full rebuild stays under 1.2 seconds on a typical laptop, and a change to a single post updates only its tag pages (usually < 200 ms).
If you notice slower rebuilds, check that you are not using expensive .Scratch or .Store operations inside the tag template; keep the template lean as shown above.
6. Limitations and how to mitigate them
- Empty tag pages: Hugo still creates
/tags/unused/index.htmleven when no post uses that tag. To avoid thin content, either setdisableKinds: ["term"]in config (disables all taxonomy term pages) or add a conditional in the template:
{{ if gt .Paginator.TotalPages 0 }}
… (normal listing) …
{{ else }}
No posts have this tag yet.
{{ end }}
Actionable closing
Enable the tag taxonomy, add a simple layouts/tag/terms.html that loops over .Paginator.Pages, and you instantly get fast, paginated archive pages for every tag. Test locally with hugo server, verify the generated public/tags/<tag>/index.html, and adjust the template or disableKinds to suit your site’s design and content policies.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.