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.
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.