AI Reading
Quick summary of this article
Preparing the AI summary…
Integrate Sanity, Contentful, or Markdown (MDX) with Next.js App Router
Modern web apps often need dynamic, editable content that’s not hardcoded. In this module, you’ll learn how to:
- Connect a Headless CMS (e.g., Sanity, Contentful, Strapi)
- Fetch content using REST or GraphQL APIs
- Render blog-style posts using MDX (Markdown + JSX)
- Compare CMS vs MDX and when to use each
🧱 Common Use Cases for CMS in Next.js
- Marketing sites – update landing page content without code
- Blogs – easily manage posts, authors, tags
- Portfolios – update projects dynamically
- Docs – power help sections with markdown or rich text
✅ Option 1: Integrate Sanity.io (or Contentful)
Step 1: Create a Free CMS Project
Visit:
Set up a new project with a “Blog” schema or use a starter template.
Step 2: Install Client SDK
Sanity:
npm install @sanity/client
Step 3: Set Up Sanity Client
// src/lib/sanity.ts
import { createClient } from '@sanity/client';
export const sanity = createClient({
projectId: 'your_project_id',
dataset: 'production',
apiVersion: '2023-01-01',
useCdn: true,
});
Step 4: Fetch CMS Data in Server Component
// src/app/blog/page.tsx
import { sanity } from '@/lib/sanity';
type Post = {
_id: string;
title: string;
slug: { current: string };
};
export default async function BlogPage() {
const posts: Post[] = await sanity.fetch(`*[_type == "post"]`);
return (
<ul className="space-y-4 p-4">
{posts.map((post) => (
<li key={post._id}>
<a href={`/blog/${post.slug.current}`} className="text-blue-600 underline">
{post.title}
</a>
</li>
))}
</ul>
);
}
✅ Contentful or Strapi would work similarly using GraphQL/REST.
✅ Option 2: Use MDX (Markdown + JSX)
Great for developers and static content blogs.
Step 1: Install MDX Support
npm install next-mdx-remote gray-matter remark remark-html
Step 2: Create Blog Posts in Markdown
/content/posts/first-post.mdx
---
title: "First Post"
date: "2025-05-01"
---
# Hello World
This is a **Markdown + JSX** post.
<MyCustomComponent />
Step 3: Parse and Render in Server Component
// src/app/blog/[slug]/page.tsx
import fs from 'fs';
import path from 'path';
import matter from 'gray-matter';
import { MDXRemote } from 'next-mdx-remote/rsc';
const POSTS_DIR = path.join(process.cwd(), 'content/posts');
export default async function BlogPost({ params }: { params: { slug: string } }) {
const filePath = path.join(POSTS_DIR, `${params.slug}.mdx`);
const raw = fs.readFileSync(filePath, 'utf-8');
const { content, data } = matter(raw);
return (
<article className="p-8 max-w-2xl mx-auto prose">
<h1>{data.title}</h1>
<MDXRemote source={content} />
</article>
);
}
✅ CMS vs MDX – Which Should You Use?
| Use Case | Choose This |
|---|---|
| Marketing site / editors | Headless CMS |
| Dev blog / docs | MDX |
| Dynamic user-generated | CMS + DB |
| Custom interactivity | MDX with components |
✅ Summary
| Feature | Tool / Example |
| CMS Integration | Sanity, Contentful, Strapi |
| Markdown Content | next-mdx-remote + gray-matter |
| Render MDX with JSX | <MDXRemote source={content} /> |
| Best for blogs/docs | MDX with static generation |
| Best for live editors | Sanity/Contentful (REST or GraphQL) |
🔜 Coming Up Next:
In Module 12, you’ll build a complete real-world project — an E-Commerce app or Developer Portfolio — using everything learned so far, including auth, CRUD, global state, and deployment.
Would you like this module also converted into Markdown blog format?
