General
CMS

Blog

Learn how to write blog posts using Content Collections.

The starter kit uses Content Collections for managing blog content. All blog posts are written using .mdx files, which combine markdown with React components.

The blog is configured in content-collections.ts and uses Fumadocs for rendering documentation-style content.

Add a new blog post

To create a new blog post, follow these steps:

  1. Create a new file Navigate to the content/posts directory and create a new .mdx file. The file name will act as the URL slug for the post. For example:

    • File name: hello-world.mdx
    • URL: https://your-app.com/blog/hello-world
  2. Add metadata At the top of the .mdx file, include a frontmatter block. This block contains key metadata about your post, written in a YAML-like format enclosed by three dashes (---). Here's an example:

content/posts/hello-world.mdx
---
title: How to create a blog post
date: 2025-01-20T12:00:00.000Z
authorName: John Doe
authorImage: /authors/john.jpg
authorLink: https://example.com
excerpt: A short description of your blog post.
tags: [Innovation, Tutorial]
published: true
content: |
  Your blog post content goes here...
---

Frontmatter Fields

The blog post schema supports the following fields:

  • title (required) - The title of the blog post
  • date (required) - ISO 8601 date string for publication date
  • authorName (required) - Name of the author
  • authorImage (optional) - URL to author's image
  • authorLink (optional) - Link to author's profile
  • excerpt (optional) - A short description/excerpt of the post
  • tags (required) - Array of tag strings
  • published (required) - Boolean to control visibility
  • image (optional) - Featured image URL
  • content (required) - The full content of the post

Using MDX Components

You can use React components directly in your MDX files. The starter kit provides several custom components:

content/posts/example.mdx
---
title: Example Post
date: 2025-01-20T12:00:00.000Z
authorName: John Doe
tags: [Example]
published: true
content: |
  # My Blog Post

  <Callout className="mt-4">This is a callout component!</Callout>

  Regular markdown content here.
---

Code Blocks

Code blocks are automatically highlighted and support line numbers:

example.ts
export function example() {
  return 'Hello, World!';
}

Images

You can include images in your blog posts:

content/posts/example.mdx
![Alt text](/path/to/image.png)

Or use the Image component for more control:

content/posts/example.mdx
import { Image } from '@/components/mdx-components';

<Image
  src="/path/to/image.png"
  alt="Alt text"
/>

Building Content

Content Collections are automatically built during the Next.js build process. During development, they are rebuilt when files change.

Querying Blog Posts

You can query blog posts in your application:

app/blog/page.tsx
import { allDocuments } from 'content-collections/generated';

export default function BlogPage() {
  const posts = allDocuments('posts')
    .filter((post) => post.published)
    .sort((a, b) => {
      const dateA = new Date(a.date);
      const dateB = new Date(b.date);
      return dateB.getTime() - dateA.getTime();
    });

  return (
    <div>
      {posts.map((post) => (
        <article key={post.path}>
          <h2>{post.title}</h2>
          <p>{post.excerpt}</p>
        </article>
      ))}
    </div>
  );
}

Configuration

The blog collection is configured in content-collections.ts:

content-collections.ts
const posts = defineCollection({
  name: 'posts',
  directory: 'content/posts',
  include: '**/*.{mdx,md}',
  schema: z.object({
    title: z.string(),
    date: z.string(),
    authorName: z.string(),
    excerpt: z.string().optional(),
    tags: z.array(z.string()),
    published: z.boolean(),
    content: z.string()
  })
});

export default defineConfig({
  collections: [posts]
});

Best Practices

  1. Use descriptive filenames - The filename becomes the URL slug
  2. Add descriptions - Help with SEO and preview cards
  3. Use categories - Organize related posts
  4. Set publication dates - Control when posts appear
  5. Test locally - Always preview posts before publishing