Web Engineering

Astro content is a real interface

2 min read

An Astro content collection looks like a folder of Markdown until you trace what depends on it.

The archive, RSS feed, search index, related-post logic, route generation, and editing scripts all consume the same shape. That shape is an interface even if nobody calls it an API.

The frontmatter is application data:

z.object({
  title: z.string(),
  excerpt: z.string(),
  category: z.string().trim(),
  author: z.string().trim(),
  draft: z.boolean().optional(),
  tags: z.array(z.string()),
  publishDate: z.string().transform((value) => new Date(value))
})

Each field has a consumer. The excerpt is the archive promise. The category groups posts. The date orders the record. The draft flag changes visibility. Optional runtime flags decide whether a page loads something expensive such as Pyodide or MathJax.

That means frontmatter is not decoration. A plausible-looking field can still be a broken contract.

The filename is part of the interface too. It becomes a route, search key, feed link, and stable identifier for editors and scripts. I prefer names that stay boring:

approval-buttons-need-context.mdx
queues-make-ai-workflows-calmer.mdx
small-sites-need-smoke-tests-too.mdx

MDX widens the contract. Once an article imports a component or mounts an island, it is source code inside the content folder. The schema can validate the frontmatter without proving that the interactive part works. The post still needs a build, a browser check, and a fallback when the component fails.

I want content checks to catch ordinary mistakes early:

  • a missing field
  • a malformed date
  • a category typo
  • a stale component import
  • an unclosed code fence
  • an image path that only works locally
  • a runtime flag omitted from a post that needs it

This matters more when an agent edits the archive. A model can produce frontmatter that reads perfectly and quietly sorts a post into the wrong place. The schema is a reviewer that does not care how confident the prose sounds.

A content system stays lightweight by making its contract explicit, not by pretending the files have no consumers.

Jeremy London

About Jeremy London

Engineering leader and builder in Denver. I write about AI platforms, agents, security, reliability, homelab infrastructure, and the parts of engineering work that have to survive production.