The site had three articles and eight standalone tag pages. That ratio was backwards: the navigation had grown larger than the body of work it was meant to organize.

Nothing was technically broken. Every tag URL rendered, the links worked, and the generator produced valid HTML. But most pages contained one or two article cards and no information of their own. I was maintaining eight destinations that existed because the generator could make them, not because a reader needed them.

The ratio was backwards

Before the change, ClearContext generated 17 HTML pages:

6  core pages: home, about, archive, privacy, terms, tags
3  articles
8  standalone tag pages
--
17 generated pages

The tags covered CLI, FFmpeg, image editing, macOS, Python, screen recording, Swift, and TUI. That taxonomy was reasonable. Giving every label a permanent page was not.

The distinction matters because tags and articles do different jobs. An article is the destination: it has original writing, a permanent URL, a self-referencing canonical, BlogPosting structured data, and a sitemap entry. A tag is navigation: it helps someone narrow the article list.

The old tag pages already used noindex,follow and were absent from the sitemap. Google's noindex documentation says that a page carrying the directive should not appear in search results after Google crawls it. Its sitemap guidance also recommends including the canonical URLs you want shown in search. The implementation was therefore signaling that the tag pages were useful paths, but not search destinations.

Before and after site architecture: eight standalone tag pages collapse into one searchable tag index while three article URLs remain unchanged

One index, many states

I replaced the eight generated pages with one searchable index at /tags/. A tag link now points to a query such as:

/tags/?tag=Python

The query is interface state, not a new article. Opening it pre-fills the tag search and lists matching posts. Clearing the search returns to the complete tag index. The main /tags/ page remains noindex,follow, so the change did not promote a navigation screen into an indexable content page.

This also kept the content model honest. Adding a tag now changes metadata and filtering behavior; it does not silently create another HTML document that needs a title, canonical policy, sitemap decision, and long-term URL support.

The redirects had a different job

Removing generated files does not make their URLs disappear from bookmarks, browser history, or links elsewhere. Each former tag path therefore returns an HTTP 301 to its matching filtered view:

/tags/python/  ->  /tags/?tag=Python
/tags/swift/   ->  /tags/?tag=Swift
/tags/tui/     ->  /tags/?tag=TUI

Google describes a permanent server-side redirect as a signal that the destination should become canonical. That is useful behavior, but it was not the reason for these redirects. The destination is deliberately not indexable. The practical goal was simpler: old links should still take a person to the same collection. Google's redirect documentation recommends permanent redirects when a move will not be reverted.

Redirect flow from an old tag page through an HTTP 301 to the matching filtered state on the consolidated tag index

What changed, and what did not

The generated site dropped from 17 pages to 9. The number of URLs intended for indexing stayed at eight: the homepage, About, Archive, Privacy, Terms, and the three articles that existed at the time of the change.

That is the least dramatic result and the most important one to state accurately. Consolidating the tags cleaned up the architecture, reduced generated output, and gave readers a better filter. It did not remove eight indexable pages, because those pages were already excluded from indexing and the sitemap. It also did not make Google index the articles faster. A sitemap helps discovery, but Google explicitly notes that inclusion does not guarantee crawling or indexing.

Comparison showing that generated pages fell from 17 to 9 while the eight intentionally indexable URLs stayed unchanged

The implementation stayed small

The shared tag helper now produces query URLs instead of directory paths. The tag page reads the query, validates it against the known tags, and applies the same filter used by interactive search. Netlify owns the permanent redirects, which keeps redirect behavior at the HTTP layer instead of relying on client-side JavaScript.

The tests assert the parts most likely to regress:

  • /tags/ renders as a distinct searchable index.
  • Tag links use the filtered query format.
  • Filtering returns the correct article cards.
  • The sitemap excludes navigation-only tag URLs.
  • Former tag paths have permanent redirect rules.

There is no second article hub hiding in the change. /archive/ remains the chronological article index, and every article keeps its own /posts/<slug>/ URL.

The rule I am keeping

A generated page should earn its URL through independent value, not merely because a data field can be expanded into a route.

That does not mean tag pages are always bad. A mature publication might build useful topic pages with original introductions, curated reading paths, or enough inventory to support real browsing. ClearContext had three articles. At that size, eight thin tag destinations were scaffolding presented as architecture.

The new rule is straightforward: articles are permanent documents; tags are filters until there is enough original material to make them something more.