Blog
Turn the docs engine into a blog: chronological posts, an RSS feed, reading-time-aware post pages and a dated archive. No extra plugins.
Stygian is a docs engine. Adding a blog means asking for one thing it does not have by default: ordering by publish date instead of by hand. Everything else - the sidebar, the theme, search, prev/next, SEO - is reused.
The wiring
Add a posts collection, tell the sidebar about it, and opt it into date
ordering:
title: My Blog
baseurl: ""
collections:
posts:
output: true
permalink: /:collection/:year/:month/:day-:title/
just_the_docs:
collections:
posts:
name: Posts
sort_by: date # chronological, newest first
stygian:
nav:
collection: posts # posts lead the sidebar
Then write posts as dated markdown in _posts/:
---
layout: blog
title: "My post"
date: 2026-03-09
excerpt: "One-line summary shown in the list, RSS and search."
tags: ["kubernetes", "devops"]
reading_time: "8 min"
---
# My post
Body goes here.
Post the date in the filename as well. The posts collection is Jekyll’s
built-in one, which requires it.
Why sort_by: date is explicit
Jekyll assigns a date to every page in every collection, defaulting to the
time the collection was scanned. A test like “sort pages that have a date”
therefore matches reference docs too, and silently reorders your installation
guide into newest-first.
For that reason a collection has to declare that it is date-driven. Setting
sort_by: date on one collection leaves every other collection on normal
nav_order and title ordering, which is the point: a site that is a blog and
its own documentation can have both without one clobbering the other.
To flip the order, add:
stygian:
nav:
date_order: asc
Newest-first is the default because that is what readers of a blog expect;
asc exists for changelogs.
Post pages
layout: blog renders a post with post metadata instead of breadcrumbs: the
publish date as a <time> element, the excerpt as the lede, and tag chips.
There is no child table of contents, because posts have no children.
Prev/next pages the posts in date order and reaches across collections, so a
post can follow a docs page when the docs collection sorts later.
Optional front matter:
| Field | Used for |
|---|---|
date |
Ordering, post meta, RSS |
excerpt |
Lede on the post, archive list, RSS description |
tags |
Chips on the post and in the archive list |
reading_time |
Rendered beside the date. Compute it yourself, or omit. |
feed_exclude |
Skip the post in the RSS feed |
post |
Set to true to opt into post rendering from any layout. |
post: true is the explicit form: it turns on the post header, the tag chips,
BlogPosting JSON-LD and prev/next, and it opts the page into the sidebar
through the default layout. Use it when you want a post that is not in
_posts - say, a dated entry in a notes collection - or when you already
have a layout chain you do not want to extend.
Archive page
_includes/post-list.html renders a dated index of every post. It is plain
Liquid over site.posts, so put it in any page whose body renders - a
layout: docs page in your collection, or a layout: page at the site root:
---
layout: docs
title: Archive
nav_order: 9
---```
The list sorts newest first and reads the same collection as the sidebar, so
it always agrees with prev/next. The include takes two optional parameters:
`limit` caps the item count and `collection` selects a different collection
(default `posts`).
## RSS feed
`feed.xml` at the theme root is a ready-made RSS 2.0 template. It is not
auto-rendered - copy it into your site's root, the same way you would copy
`404.md`:
```shell
cp <theme>/feed.xml ./feed.xml
It pulls from site.posts when a posts collection exists, otherwise from the
sidebar collection filtered to pages carrying a date. It honors
feed_exclude: true, and stygian.feed.limit caps the item count
(default 50).
The template ships in the gem and in the repository, so it is available to
copy from either. This is the same convention as 404.md.
What this does not do
Tag browsing is not included. Liquid cannot group a set of posts by an array
field - a per-tag index needs a Ruby data structure, and a theme cannot
register Jekyll hooks, because hooks load from the consumer’s site root, not
the theme’s. If you want tag pages, add one yourself: it is a single Ruby file
plus a page, and the .post-tag styling is already there.
reading_time is not computed either, for the same reason.