komal.nakrani
Browse Themes
ThemesCategoriesDocsBlog
Docs/Working With Your Theme/Content Collections

Content Collections

How journal posts and other Markdown content are defined, validated and queried.

Updated: September 2026·License: Commercial & Personal

Defining a collection

Collections give your Markdown a schema, so a missing or misspelled frontmatter field fails the build instead of the page:

ts
// src/content.config.ts
import { defineCollection, z } from 'astro:content';
import { glob } from 'astro/loaders';

const journal = defineCollection({
  loader: glob({ pattern: '**/*.{md,mdx}', base: './src/content/journal' }),
  schema: z.object({
    title: z.string(),
    description: z.string(),
    publishDate: z.coerce.date(),
    draft: z.boolean().default(false),
  }),
});

export const collections = { journal };

Writing an entry

markdown
---
title: "Notes from the four o'clock shift"
description: "Working notes on topology and look development."
publishDate: 2026-02-14
---

Body copy starts here.

Querying entries

astro
---
import { getCollection } from 'astro:content';

const posts = (await getCollection('journal', ({ data }) => !data.draft))
  .sort((a, b) => b.data.publishDate.valueOf() - a.data.publishDate.valueOf());
---
<ul>
  {posts.map((post) => (
    <li>
      <a href={`/journal/${post.id}/`}>{post.data.title}</a>
    </li>
  ))}
</ul>

The filter callback runs at build time, so drafts never reach the output at all.

Explore production-ready themes

Hand-built Astro themes — SaaS, storefront, portfolio, and dashboard.

Browse All Themes ➔