· Mark Lester Mahilum · Resources · 1 min read
draft: true in frontmatter does nothing unless you filter for it
Astro Content Collections don't hide draft posts automatically. Forgetting the filter on index and slug pages means drafts are publicly live.
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.
Next step
Related: why I merged a small content collection into the blog instead of keeping it separate. If your Astro site needs a second pair of eyes, that is what consulting is for. Book a call.