John Dalesandro

Astro: Manage Draft and Published Post Statuses by Adding a Content Collection Schema Property

In this guide, I will walk through how to incorporate a draft property into your content collection schema in Astro, allowing you to manage unpublished draft posts separately from published ones. By adding a boolean property to the schema and configuring a filter to exclude draft posts in production, you can easily control which blog entries are visible in different environments. Whether you’re working in development, preview, or production, this setup ensures that draft content remains hidden in live sites while remaining accessible during the development process.

Astro - Draft and Published Posts

Instructions

Define Draft Property in Content Collection Schema

Start by updating the blog content collection schema in content.config.ts to add an optional draft boolean property.

draft: z.boolean().optional()

Each blog collection entry’s frontmatter can now use the draft property to mark the entry as either a draft (true) or published (false or not defined).

import { glob } from 'astro/loaders';
import { defineCollection, z } from 'astro:content';

const blog = defineCollection({
  loader: glob({ base: './src/content/blog', pattern: '**/*.{md,mdx}' }),
  schema: z.object({
    title: z.string(),
    pubDate: z.coerce.date(),
    draft: z.boolean().optional(),
  }),
});

export const collections = { blog };

Add Draft Property Filter

Add the following filter to getCollection() to exclude entries with the draft property set to true in the PROD environment.

.filter((post) => import.meta.env.PROD ? post.data.draft !== true : true)

For example, the blog collection is filtered to exclude drafts from the production environment and sorted by published date in descending order.

const posts = (await getCollection('blog'))
	.filter((post) => import.meta.env.PROD ? post.data.draft !== true : true)
	.sort((a, b) => b.data.pubDate.valueOf() - a.data.pubDate.valueOf())

Include Draft Status in Frontmatter

The draft property can now be added to the frontmatter of blog collection entries. If not set, the entry is assumed to be published and included in production builds.

---
title: ''
pubDate: ''
draft: true
---

Results

In development (npm run dev), all blog entries are shown, regardless of draft status. In preview (npm run preview) and production (npm run build), entries with draft set to true are excluded if filters are applied to getCollection().

Summary

By adding a draft property to your content collection schema and configuring a filter to exclude draft posts in production, you gain greater control over which blog entries are displayed in different environments. This approach ensures that draft content is excluded from production releases while remaining visible during development.