200+ Website Templates Built with Modern Stacks | Themefisher

How to Create Draft Posts or Pages in Astro

By Farhad| Last Updated: 06 Jun, 2026|03 Mins read
How to Create Draft Posts or Pages in Astro

TL;DR

  • Astro has no built-in draft system, so you add one manually using a draft: true frontmatter property and a build-time filter.
  • Draft posts are hidden by default at build time; they only appear when you run the build with a --buildDrafts argument.
  • You need to handle drafts in three places: the content schema, the collection query, and any page entry points.

Why Astro Needs a Manual Draft System

Astro does not ship with a draft feature. If you publish a content collection without filtering, every file in that folder gets built and served, including work-in-progress posts.

The workaround is a frontmatter property combined with a build-time filter. It takes about five minutes to set up and gives you the same behavior you would expect from a CMS draft system.

This guide is based on how the draft system is implemented in Astroplate, a free Astro starter template built with Astro, Tailwind CSS, and TypeScript. If you want a working reference, the full implementation is available there.

Step 1: Add a draft Property to Your Frontmatter

In any Markdown or MDX file you want to hide from the published build, add draft: true to the frontmatter:

---
title: "My Draft Post"
description: "This post is a draft."
draft: true
---

Leave the field out entirely on published posts. The field is optional, so Astro will not throw an error if it is missing.

Step 2: Add draft to the Content Schema

In content.config.ts, define draft as an optional boolean so Astro accepts it without a schema validation error:

draft: z.boolean().optional()

Without this, Astro may warn or error when it encounters the draft field in your frontmatter.

Step 3: Filter Drafts in Your Collection Query

The main filtering logic goes in contentParser.astro (or wherever you call getCollection). Check for a --buildDrafts argument in the build process and exclude drafts when it is absent:

const buildDrafts = process.argv.includes("--buildDrafts");

const allPages = await getCollection(collectionName, ({ data, id }) => {
  if (!buildDrafts && (data as PageData)?.draft) {
    return false;
  }
  return !id.startsWith("-");
});

This keeps draft posts out of every page that uses the collection - index pages, category pages, RSS feeds, and anything else that loops over your content.

Step 4: Block Draft Pages at the Route Level

Filtering the collection covers list views, but a user who knows the URL can still access a draft page directly if you do not also block it at the route level.

In index.astro and [slug].astro, add this check after you retrieve the page data:

const buildDrafts = process.argv.includes("--buildDrafts");

if (!buildDrafts && postIndex.data.draft) {
  return Astro.redirect("/404");
}

This redirects anyone who hits the URL of a draft page to a 404 unless the build was explicitly run with draft support.

Step 5: Build with Drafts Included

To preview draft content during development or a staging build, pass the --buildDrafts argument:

npm run build -- --buildDrafts

This tells every filter in the project to include draft items. Remove it for production builds.

How the Pieces Work Together

This draft system has four parts, each covering a different surface:

PartWhat it covers
draft: true in frontmatterMarks the content file as a draft
draft in content schemaPrevents Astro schema validation errors
Filter in getCollectionHides drafts from list pages and feeds
Redirect in [slug].astroBlocks direct URL access to draft pages

All four need to be in place for drafts to be fully hidden in a production build.

You can see this entire pattern implemented in Astroplate - a free, open-source Astro starter template by Zeon Studio. It is a good starting point if you want draft support, search indexing, and content collections already wired up together.

Frequently Asked Questions

Does Astro have a built-in draft mode?

No. As of Astro 6, there is no native draft feature. You need to add one manually using a frontmatter property and a build-time filter, as described in this guide.

Can I preview draft posts in astro dev mode?

Yes, but only if you also update your dev server config to pass --buildDrafts, or you temporarily remove the draft filter during local development. The filter checks process.argv, so it applies in both dev and build modes.

Do I need to add the frontmatter field to every published post?

No. The draft field is optional in the schema. Posts without a draft field are treated as published by default.

Is there a working example of this draft system I can reference?

Yes. Astroplate is a free Astro starter template by Zeon Studio that has this draft system fully implemented. It covers the content schema, collection filter, route-level redirect, and JSON exclusion out of the box.

Can I use this pattern with MDX files?

Yes. The draft frontmatter property and the getCollection filter work the same way for both .md and .mdx files.

    SHARE
  • Copied!