Move posts from siteConfig.blog to MDX, Contentful, or Sanity.
The blog ships with demo posts stored in config so it works the moment you clone. When you're ready for a real content workflow, move posts to MDX or a CMS.
Posts live in siteConfig.blog as structured objects with a Markdown body. The index, category filters, and individual post pages all read from that array.
{
slug: "async-standups-that-stick",
title: "Async standups that actually stick",
excerpt: "Three habits that keep async standups alive past week two.",
date: "2026-04-18",
category: "Practices",
author: "Maya Okafor",
body: "## The first habit\n\nMake it…",
}
This is great for a launch — zero infrastructure, fully static. It's less great once non-engineers need to publish.
For a developer-owned blog, move each post to its own .mdx file under content/blog/:
content/blog/<slug>.mdx with frontmatter for the metadata.getBlogPosts() instead of the config array.For a marketing team that publishes without a deploy, point the blog at a headless CMS. Loop's data layer is a single function — swap its body to fetch from the CMS.
export async function getBlogPosts() {
const entries = await cms.fetch("blogPost", { order: "-date" });
return entries.map(toBlogPost);
}
Whatever source you choose, return the same BlogPost interface. Because the UI only depends on that contract, you can change the backend without touching a single component.
Don't need a blog? Delete the blog routes, drop the blog array from config, and remove the Blog nav item. Nothing else references it.