TIL

draft: true in frontmatter does nothing unless you filter for it


Schema had draft: z.boolean().default(false) on blog posts. I assumed that meant draft posts stayed hidden. It doesn’t. Astro’s getCollection('blog') returns every entry regardless of the draft field. The field is just data. Nothing reads it unless you tell it to, and I found that out when a half-written post showed up on the live index.

Found the index page and the [...slug].astro page both had no draft check, so any post with draft: true was reachable at its URL and listed on the index.

Fix is a one-line filter wherever posts are pulled:

const posts = (await getCollection('blog')).filter((p) => !p.data.draft);

You need it in both places: the index (list view) and the [...slug] page (direct URL access). Filtering only the index still leaves the direct link public, which is the part that bit me. A post missing from the list feels hidden, but the URL is still live for anyone who has it.

Mark Lester Mahilum

Mark Lester Mahilum

Claude Code expert based in the Philippines. Building AI-native workflows for businesses and documenting what actually works.