WebGrid blog posts can now live in subfolders, and that change ended up cleaning up more than just file organization.

This release also tightens blog ordering, adds a temporary web toggle for non-public post states, and makes frontmatter validation stricter so broken titles fail during checks instead of slipping through quietly.

What shipped

  • Recursive blog loading now supports nested folders under content/blog/
  • Blog routing now supports nested slugs through a catch-all post route
  • Blog sorting stays date-first, with same-series same-day posts staying grouped by series order
  • The blog index now has a checkbox to reveal draft, private, and archived posts
  • Blog frontmatter validation now errors when an unquoted title contains :
  • Reusable release notes now have a dedicated template file outside the blog feed

Why this matters

Before this change, blog content was effectively trapped in one flat folder, and the minute we started writing Building in Public posts in subfolders the routing assumptions showed up fast.

That also exposed a second problem: the blog flow had a few hidden rules that were too brittle. Sorting behavior mixed date with other grouping assumptions, invalid frontmatter could sneak by because the parser was too permissive, and there was no temporary way to inspect non-public posts in the web UI.

Now the blog system behaves more like an actual publishing system instead of a folder convention that happened to work. Posts can be organized into nested paths, routes match that structure, date stays the primary sort signal, and frontmatter mistakes fail loudly enough to catch before release.

Changelog

Blog subfolders now work end to end

The blog loader now walks nested directories under content/blog/, and post slugs are generated from the relative folder path instead of assuming every file lives at the top level. Routing was updated to a catch-all blog post page so nested content resolves correctly on the site.

Sorting now stays anchored to publish date

The blog flow now treats date as the primary ordering rule. When multiple posts from the same series land on the same day, the series still keeps its internal entry order so grouped posts do not shuffle into nonsense.

Non-public statuses are temporarily visible from the web index

The blog index now includes a checkbox that reveals draft, private, and archived posts. It is a temporary inspection tool, not a final publishing model, but it gives immediate visibility while the longer-term content-status plan is still open.

Frontmatter validation is stricter now

If a blog post uses an unquoted title with :, checks now fail. That is intentional. It catches invalid YAML-like frontmatter before a bad title turns into a parsing edge case later in the build.

Validation snapshot

  • npm run check should fail on invalid blog frontmatter instead of silently accepting it
  • Blog routes now support nested paths like building in public/...
  • The all-status toggle is intentionally temporary and only applies to the blog index for now

The short version

The blog now behaves like a real content system, not a flat-folder accident.