A Complete Guide to Series
Table of Contents
Learn how to organize your posts into sequential series, perfect for tutorials, courses, and multi-part stories. A series organizes related posts in a sequential order, similar to chapters in a book. Unlike tags, which simply group related content, series suggest a specific reading order from start to finish. Posts within a series do not need to be published consecutively; the series feature brings together thematically linked posts in a coherent sequence. The diagram below illustrates how series posts (3, 5, and 8) exist within the main blog flow while maintaining their own ordered sequence within Series 1. Create a directory for your series. Create Set up the Create your series articles in this directory. Want more? Keep reading! A series is just a section which is handled in a special way by tabi. For more details on sections, see the Zola documentation. Taking the example from the diagram above, the directory structure would be as follow: To create a series, you need to: The series main page displays an overview followed by a list of all posts in the series: If the content of a series (the Markdown after the front matter in To force the feature on or off, set All pages in the series section will be a series page. The series pages will be ordered as per the series section While series maintain their own internal order, they remain independent from the main section’s (e.g. Choose from these sorting methods, each with its own advantages: In order to properly reverse dates, Zola v0.19.3+ (unreleased) is required so that pagination information is available through the Pages in a series are indexed starting from 1, following their This setting follows the hierarchy. Series articles can have automatic introduction and conclusion sections. These are configured in your series’ The intro and outro sections each have their own CSS classes ( The series system uses different templates based on an article’s position in the series: The system automatically determines which template to use based on the article’s position. The templates are defined in the series configuration ( All templates are optional. Template selection follows a priority system: See the template example for a more elaborate example. By default: You can control exactly where these appear using Series templates use a flexible variable system that lets you: Variables are placeholders starting with There are three types of variables: Markdown links like Use HTML variables (ending in Series templates support custom variables for additional information you want to include across your series. The process takes two steps: You can use your custom variables in any template, alongside the built-in variables: While placeholders are defined with uppercase ( This will output: If you use a placeholder in your templates but don’t provide its value in
flowchart
subgraph main[BLOG]
P1[Post 1]
P2[P2]
P3[P3]
P4[P4]
P5[P5]
P6[P6]
P7[P7]
P8[P8]
P9[P9]
end
subgraph series1[SERIES 1]
PS1["Series Post 1 (=P3)"]
PS2["Series Post 2 (=P5)"]
PS3["Series Post 3 (=P8)"]
end
P3 o-.-o PS1
P5 o-.-o PS2
P8 o-.-o PS3
Quick Start
_index.md
in the series directory._index.md
front matter:= "Learning Rust"
= "series.html"
= "slug"
= true
[]
= true
How Do Series Work?
content/
_index.md
blog/
_index.md
post1/
index.md
post2/
index.md
post4/
index.md
post6/
index.md
post7/
index.md
post9/
index.md
series1/
_index.md
post3/
index.md
post5/
index.md
post8/
index.md
series.html
templateseries = true
in the section’s [extra]
configurationtransparent = true
to integrate series posts with the parent blog section Jump to Posts
_index.md
) is over 2000 characters, a “Jump to posts” link appears next to the series title.show_jump_to_posts
in the [extra]
section of your series section or in config.toml
. This setting follows the hierarchy. Series Pages and Order
sort_by
.blog/
) chronological flow thanks to the transparent
setting. Sorting Options
sort_by
pros cons slug
The series pages order is made explicit in the path (e.g. example.com/blog/series1/01-series-post-one
).Each series page must be prefixed accordingly. weight
The series pages order is easy to set up transparently.
First series post has weight 1
, second series post has weight 2
and so on.Each series page must have its weight set accordingly. date
The series pages order can be configured once in the series section configuration. No need to do anything on each series page. The series pages order has to be reversed because the first page is usually the oldest. This can only be achieved by paginating the series section ( paginate_by = 9999
) and reversing its order (paginate_reversed = true
).get_section
function. Anything relying on the series pages order won’t be correct in a series page otherwise (e.g. previous/next series page, ordered and unordered list…) See Zola PR #2653. Page Indexing
sort_by
order. To reverse the indexing (making the first page have the highest index instead), add this setting to _index.md
or config.toml
:[]
= true # Defaults to false if unset.
Intro and Outro Templates
_index.md
. A basic example:[]
= "This article is part of the $SERIES_HTML_LINK series."
[]
= "Thanks for reading part $SERIES_PAGE_INDEX of $SERIES_HTML_LINK!"
series-page-intro
and series-page-outro
), allowing you to customize their appearance through custom CSS. Template Types
next_only
- Used for the first article (has next article but no previous)middle
- Used for articles with both previous and next articlesprev_only
- Used for the last article (has previous article but no next)default
- Fallback template used when a specific position template isn’t defined_index.md
), as extra.series_intro_templates
and extra.series_outro_templates
.:[]
= "Welcome to part 1! Next up: $NEXT_HTML_LINK"
= "Previous: $PREV_HTML_LINK | Next: $NEXT_HTML_LINK"
= "The final chapter! Previously: $PREV_HTML_LINK"
= "Part $SERIES_PAGE_INDEX of $SERIES_PAGES_NUMBER"
next_only
, middle
, or prev_only
), it will be useddefault
template is used Placement in Content
<!-- series_intro -->
and <!-- series_outro -->
in your Markdown:
Variables
$
that get replaced with actual content when your site builds. For example, $SERIES_HTML_LINK
becomes a clickable link to your series index page. Basic Series Variables
Variable Availability Returns Description Example Usage Example Output $SERIES_TITLE
Always Text Plain text title of the series Part of $SERIES_TITLE
Part of Learn Rust $SERIES_PERMALINK
Always Text URL to series index [See all posts]($SERIES_PERMALINK)
See all posts $SERIES_HTML_LINK
Always HTML Ready-to-use link to series Welcome to $SERIES_HTML_LINK!
Welcome to Learn Rust! $SERIES_PAGES_NUMBER
Always Number Total articles in series A $SERIES_PAGES_NUMBER part series
A 5 part series $SERIES_PAGE_INDEX
Always Number Current article’s position Part $SERIES_PAGE_INDEX of $SERIES_PAGES_NUMBER
Part 3 of 5 $SERIES_PAGES_OLIST
Always HTML Ordered list of all articles Articles in series: $SERIES_PAGES_OLIST
Articles in series: $SERIES_PAGES_ULIST
Always HTML Unordered list of all articles Articles in series: $SERIES_PAGES_ULIST
Articles in series: [text]($SERIES_PERMALINK)
will be marked (and styled) as external. If you need custom text and want to avoid external styling, use HTML: <a href=\"$SERIES_PERMALINK\">your text</a>
. Navigation Variables
Variable Availability Returns Description Example Usage Example Output $PREV_TITLE
Previous exists Text Previous article’s title Previously: $PREV_TITLE
Previously: Setting Up Your Environment $PREV_PERMALINK
Previous exists Text URL to previous article [← Back]($PREV_PERMALINK)
← Back $PREV_HTML_LINK
Previous exists HTML Ready-to-use link to previous Read $PREV_HTML_LINK first
Read Setting Up Your Environment first $PREV_DESCRIPTION
Previous exists Text Description of previous article Recap: $PREV_DESCRIPTION
Recap: Setting up Rust $NEXT_TITLE
Next exists Text Next article’s title Next up: $NEXT_TITLE
Next up: Advanced Patterns $NEXT_PERMALINK
Next exists Text URL to next article [Continue →]($NEXT_PERMALINK)
Continue → $NEXT_HTML_LINK
Next exists HTML Ready-to-use link to next Continue with $NEXT_HTML_LINK
Continue with Advanced Patterns $NEXT_DESCRIPTION
Next exists Text Description of next article Coming up: $NEXT_DESCRIPTION
Coming up: Learn about Rust’s advanced pattern matching features First Article Reference
Variable Availability Returns Description Example Usage Example Output $FIRST_TITLE
Always Text First article’s title Start with $FIRST_TITLE
Start with Introduction to Rust $FIRST_HTML_LINK
Always HTML Ready-to-use link to first article Begin at $FIRST_HTML_LINK
Begin at Introduction to Rust Template Example
_HTML_LINK
) when you want ready-made links. Use text variables (ending in _TITLE
or _PERMALINK
) when you want more control over the formatting.# Introduction.
[]
= """
Welcome to $SERIES_HTML_LINK! This $SERIES_PAGES_NUMBER-part series will teach you Rust from scratch.
Up next: $NEXT_HTML_LINK - $NEXT_DESCRIPTION
"""
= """
📚 Part $SERIES_PAGE_INDEX of $SERIES_PAGES_NUMBER in $SERIES_HTML_LINK
Previously: $PREV_HTML_LINK
Next up: $NEXT_HTML_LINK
"""
= """
Welcome to the final part of $SERIES_HTML_LINK!
New here? Start with $FIRST_HTML_LINK to build a strong foundation.
Previously: $PREV_HTML_LINK
"""
# Fallback template.
= "This article is part of the $SERIES_HTML_LINK series."
# Outro.
[]
= """
Thanks for reading! 🙌
Continue your journey with $NEXT_HTML_LINK, where $NEXT_DESCRIPTION
Or check out the complete [$SERIES_TITLE]($SERIES_PERMALINK) series outline.
"""
= """
---
📝 Series Navigation
- Previous: $PREV_HTML_LINK
- Next: $NEXT_HTML_LINK
- [Series Overview]($SERIES_PERMALINK)
"""
= """
🎉 Congratulations! You've completed $SERIES_HTML_LINK.
Want to review? Here's where we started: $FIRST_HTML_LINK
Or check what we just covered in $PREV_HTML_LINK.
"""
# Fallback.
= """
---
This article is part $SERIES_PAGE_INDEX of $SERIES_PAGES_NUMBER in $SERIES_HTML_LINK.
"""
Custom Variables
_index.md
):[]
= true
= ["$POSITION", "$TOPIC", "$DIFFICULTY"]
series_template_variables
:[]
= "first"
= "Variables and Types"
= "Beginner"
Using Custom Variables
[]
= """
This is the $POSITION article in $SERIES_HTML_LINK.
Today's topic: $TOPIC
Difficulty level: $DIFFICULTY
"""
$POSITION
), the variable names in series_template_variables
must be lowercase (position
). Example with Custom Variables
# In the series configuration.
[]
= true
= ["$LEARNING_TIME", "$KEY_CONCEPTS"]
= """
📚 Part $SERIES_PAGE_INDEX of $SERIES_PAGES_NUMBER
⏱️ Estimated time: $LEARNING_TIME
🔑 Key concepts: $KEY_CONCEPTS
"""
# In an article of the series.
[]
= "30 minutes"
= "Functions, Error Handling, Pattern Matching"
📚 Part 2 of 5
⏱️ Estimated time: 30 minutes
🔑 Key concepts: Functions, Error Handling, Pattern Matching
series_template_variables
, the build will fail with an error listing the missing variables.