Best CMS for Next.js App Router 2026: We Tested 6 in Production
I've been shipping Next.js sites since the Pages Router days, and I've lost count of how many times I've seen a "best CMS" article written by someone who clearly installed the thing once, followed the quickstart tutorial, and called it a review. This isn't that.
At Social Animal, we run production sites across multiple CMS architectures -- from Payload CMS powering a healthcare app to Supabase serving 253,000+ pages across three different platforms. We've evaluated Strapi 5, Sanity, and Contentful for real client projects. And this very site you're reading? It's built on MDX files committed to a Git repo.
So when I say "we tested 6 in production," I mean we've dealt with the migration headaches, the build time surprises, the 3 AM Slack messages about content not publishing. Here's everything we've learned about choosing the right CMS for Next.js App Router in 2026.
Table of Contents
- Why the App Router Changes the CMS Equation
- The 6 CMSs We Tested (and How We Tested Them)
- 1. Payload CMS 3 -- Best Overall for Next.js
- 2. Supabase-as-CMS -- Best for Scale (10K+ Pages)
- 3. Strapi 5 -- Best for Non-Technical Teams
- 4. Sanity -- Best for Real-Time Collaboration
- 5. Contentful -- Best for Enterprise (With Budget)
- 6. Markdown/MDX -- Best for Developer Blogs
- Production Metrics Comparison
- Decision Framework: How to Pick Your CMS
- What We'd Do Differently
- FAQ

Why the App Router Changes the CMS Equation
If you're still thinking about CMS selection the way you did with the Pages Router, you're leaving performance on the table. The App Router fundamentally changed how data flows through a Next.js application, and that has direct implications for which CMS fits best.
Here's what matters now:
Server Components are the default. Your CMS data fetching happens on the server without shipping any JavaScript to the client. This means CMSs with native Node.js SDKs or -- even better -- local APIs that skip the network entirely have a massive advantage.
React Server Components + fetch caching. The App Router's built-in fetch deduplication and caching means your CMS integration patterns look completely different. You're not reaching for getStaticProps or getServerSideProps anymore. You're writing async components that call your CMS directly.
Parallel Routes and Intercepting Routes. These patterns unlock CMS-driven layouts that were painful to build before. A CMS that supports flexible content modeling (not just blog posts and pages) shines here.
Partial Prerendering (PPR). As of Next.js 15, PPR lets you serve a static shell with dynamic holes. This changes the ISR vs. SSR debate entirely, and it means your CMS revalidation strategy matters more than ever.
With all of that context, let's get into the actual testing.
The 6 CMSs We Tested (and How We Tested Them)
Our evaluation wasn't theoretical. For each CMS, we either shipped production pages or did a deep technical evaluation for a real client project. We measured:
- Developer experience with App Router specifically
- Build times at various page counts
- Content editor UX for non-developer team members
- Pricing at scale (not just the free tier)
- TypeScript integration quality
- Revalidation patterns (ISR, on-demand, webhooks)
Let's go through each one.
1. Payload CMS 3 -- Best Overall for Next.js
Our verdict: Best developer experience for Next.js App Router, period.
Payload CMS 3 is the one that made me rethink what a CMS could be. It's not a separate service you call over HTTP. It lives inside your Next.js application. Same repo, same deployment, same TypeScript types.
We run Payload 3 in production on SleepDr, a healthcare platform with 228 pages, multi-level access control, and content that needs to be accurate (it's health-related, so wrong content isn't just a bad look -- it's a liability).
What Makes Payload Special for App Router
The Local API is the killer feature. Instead of making HTTP requests to your CMS, you import a function and call it directly:
// app/blog/[slug]/page.tsx
import { getPayload } from 'payload'
import config from '@payload-config'
export default async function BlogPost({ params }: { params: { slug: string } }) {
const payload = await getPayload({ config })
const posts = await payload.find({
collection: 'posts',
where: {
slug: { equals: params.slug },
status: { equals: 'published' },
},
})
const post = posts.docs[0]
if (!post) notFound()
return <Article post={post} />
}
No network hop. No REST or GraphQL overhead. No SDK to install. The function call is fully typed because Payload generates TypeScript interfaces from your collection configs. When you refactor a field name, your IDE catches every broken reference instantly.
Live Preview with App Router
Payload 3's live preview works with Server Components. Your content editors see changes in real-time on the actual site layout -- not some approximation in the admin panel. We configured this for SleepDr and the editorial team went from "I need a developer to check this" to self-sufficient publishing within a week.
Access Control That Actually Works
Payload's field-level and collection-level access control is defined in code:
const Posts: CollectionConfig = {
slug: 'posts',
access: {
read: () => true,
create: ({ req: { user } }) => user?.role === 'editor' || user?.role === 'admin',
update: ({ req: { user } }) => user?.role === 'admin',
delete: ({ req: { user } }) => user?.role === 'admin',
},
fields: [
// ...
],
}
For a healthcare app, this granularity isn't optional. It's a requirement.
The Tradeoffs
Payload runs on your infrastructure. If you want a fully managed SaaS experience, Payload Cloud exists (starting around $35/month for production), but you're still responsible for understanding the deployment. It's also a Node.js runtime dependency, which means your hosting needs to support it (Vercel works, but costs climb with persistent connections to your database).
For our Next.js development work, Payload 3 is now our default recommendation for content-heavy sites under 5,000 pages.

2. Supabase-as-CMS -- Best for Scale (10K+ Pages)
Our verdict: Not technically a CMS, but nothing else comes close for massive structured datasets.
This is the unconventional pick, and it's the one I'm most excited about. Supabase isn't marketed as a CMS. It's a PostgreSQL platform with auth, storage, and Edge Functions. But when your "content" is really structured data -- celebrity profiles, business listings, product databases -- traditional CMSs fall apart at scale, and Supabase doesn't even break a sweat.
We run three production sites on Supabase-as-CMS:
- DA -- 91,000+ pages of celebrity data across 30 languages
- NAS -- 137,000+ business listings
- HostList -- 25,000+ hosting provider listings
That's 253,000+ pages. Let me tell you what happens when you try to put 91,000 entries into a traditional headless CMS: the admin panel becomes unusable, build times go to infinity, and your bill goes through the roof.
The Architecture
We don't use generateStaticParams for 253K pages. We use fully dynamic rendering with aggressive caching:
// app/[locale]/celebrity/[slug]/page.tsx
import { createClient } from '@/lib/supabase/server'
export default async function CelebrityPage({ params }: Props) {
const supabase = await createClient()
const { data: celebrity } = await supabase
.from('celebrities')
.select('*, social_profiles(*), net_worth_history(*)')
.eq('slug', params.slug)
.eq('locale', params.locale)
.single()
if (!celebrity) notFound()
return <CelebrityProfile data={celebrity} />
}
export const revalidate = 86400 // Revalidate daily
Build time? About 10 seconds. The pages are rendered on-demand and cached at the edge. When someone searches for a celebrity we haven't served recently, the first request hits Supabase (typically 20-50ms from the edge), renders the page, caches it, and every subsequent visitor gets the cached version.
Row-Level Security as Access Control
Supabase's RLS policies replace what you'd normally build in a CMS admin:
CREATE POLICY "Public read access" ON celebrities
FOR SELECT USING (status = 'published' AND locale = current_setting('app.locale'));
CREATE POLICY "Editor update access" ON celebrities
FOR UPDATE USING (auth.role() = 'editor');
The Content Editing Problem
Here's the honest downside: Supabase's Table Editor is fine for developers, but it's not a content editing experience. We built custom admin interfaces for our editorial teams using Supabase's client libraries. If you don't want to build your own admin UI, this approach isn't for you.
Supabase Pro runs $25/month, and even at 253K pages, we're nowhere near the compute or storage limits. Compare that to Contentful or Sanity pricing at similar scale.
For our headless CMS development solutions, we recommend this approach for any project above 10,000 structured content pages.
3. Strapi 5 -- Best for Non-Technical Teams
Our verdict: The best visual content modeling experience, ideal when your editors aren't developers.
We evaluated Strapi 5 in depth for a client project and wrote an extensive Payload vs Strapi comparison (which ranks on page 1, so clearly others are asking the same questions). While we ultimately went with Payload for that project, Strapi has a clear use case.
Strapi 5's Content-Type Builder lets non-technical team members create and modify content structures through a drag-and-drop GUI. No code. No config files. No deployments. Your marketing manager can add a "testimonial" content type with fields for quote, author, company, and rating without filing a Jira ticket.
App Router Integration
Strapi 5 exposes both REST and GraphQL APIs. The integration with App Router is straightforward but requires network requests:
// lib/strapi.ts
export async function getArticles() {
const res = await fetch(
`${process.env.STRAPI_URL}/api/articles?populate=*`,
{
headers: { Authorization: `Bearer ${process.env.STRAPI_TOKEN}` },
next: { revalidate: 60 },
}
)
return res.json()
}
It works. But compared to Payload's Local API, you feel the impedance mismatch. You're serializing and deserializing data that could have stayed in-process. TypeScript types need to be generated separately (Strapi has a CLI for this, and it's gotten better in v5).
Strapi 5 Pricing (2026)
| Plan | Price | Seats | Assets |
|---|---|---|---|
| Community | Free (self-hosted) | Unlimited | Unlimited |
| Team | $29/month/seat | 5-20 | 100GB |
| Business | $99/month/seat | Custom | 500GB |
| Enterprise | Custom | Custom | Custom |
Self-hosting Strapi is genuinely free and works well. The Cloud plans add managed hosting and premium support.
4. Sanity -- Best for Real-Time Collaboration
Our verdict: Best real-time editing experience, but GROQ is a love-it-or-hate-it commitment.
We evaluated Sanity seriously for the DA project (91K celebrity pages) before going with Supabase. Sanity Studio is genuinely impressive -- it's a React application you can customize down to the field level. Real-time collaboration works flawlessly. Two editors can work on the same document simultaneously, Google Docs-style.
GROQ: Powerful but Polarizing
Sanity uses GROQ, its own query language:
*[_type == "article" && slug.current == $slug][0] {
title,
body,
"author": author->{ name, image },
"categories": categories[]->{ title, slug },
publishedAt
}
GROQ is actually elegant once you learn it. The projection syntax (->) for resolving references is nicer than GraphQL for many use cases. But it's another query language your team needs to learn and maintain. And when you hit edge cases, the documentation can feel thin.
Why We Didn't Choose Sanity for DA
At 91,000 documents, Sanity's pricing becomes significant. The Growth plan ($15/user/month) includes 1M API CDN requests. Sounds like a lot until you realize a site with 91K pages generating decent traffic chews through that quickly. We estimated our monthly Sanity bill would be $300-500/month for DA alone. Supabase Pro at $25/month was a no-brainer.
Sanity is excellent for sites with 50-5,000 content items where multiple editors need to collaborate. Editorial teams at media companies love it.
5. Contentful -- Best for Enterprise (With Budget)
Our verdict: The most mature headless CMS, but you'll pay for that maturity.
Contentful has been around since 2013. It's the headless CMS that enterprise teams default to, and there's a reason: the content modeling is excellent, the API is rock-solid (99.99% SLA on Premium), and the ecosystem of integrations is unmatched.
We've evaluated Contentful for multiple enterprise client projects. The content model builder is polished, the API explorer in the web app is genuinely useful for debugging, and the webhooks system integrates cleanly with Next.js on-demand revalidation.
The Price Tag
| Plan | Price (2026) | Content Types | Locales | API Calls |
|---|---|---|---|---|
| Free | $0 | 48 | 2 | 1M/month |
| Basic | $300/month | 48 | 6 | 2M/month |
| Premium | Custom (typically $3,000+/month) | Unlimited | Unlimited | Custom |
The jump from Free to Basic is steep. The jump from Basic to Premium is a cliff. If you're an enterprise with a $50K+/year SaaS budget, Contentful is a safe bet. If you're a startup trying to keep burn rate low, look elsewhere.
App Router Integration
Contentful's JavaScript SDK works well with Server Components:
import { createClient } from 'contentful'
const client = createClient({
space: process.env.CONTENTFUL_SPACE_ID!,
accessToken: process.env.CONTENTFUL_ACCESS_TOKEN!,
})
export async function getPage(slug: string) {
const entries = await client.getEntries({
content_type: 'page',
'fields.slug': slug,
include: 3,
})
return entries.items[0]
}
The SDK is well-maintained and fully typed with contentful-typescript-codegen. No complaints on the DX front.
6. Markdown/MDX -- Best for Developer Blogs
Our verdict: Zero overhead, maximum control, Git-native workflows.
This site -- socialanimal.dev -- runs on MDX. Every article is a file in the repo with frontmatter metadata:
---
title: "Best CMS for Next.js App Router 2026"
slug: "best-cms-nextjs-app-router-2026"
category: "Resources"
tags: ["nextjs", "cms", "payload", "supabase"]
publishedAt: "2026-01-15"
---
I've been shipping Next.js sites since the Pages Router days...
With @next/mdx or contentlayer2 (the community fork), MDX integrates natively with the App Router. Your content IS your codebase. Version control, branching, pull request reviews -- all the workflows you already know.
When MDX Breaks Down
Non-developers can't use it. Period. If your marketing team needs to publish blog posts, MDX means they're either learning Git or you're building them an editing interface (at which point, just use Payload).
MDX also doesn't scale to thousands of pages well. At around 500+ MDX files, build times start to drag and your IDE slows down. For a company blog or documentation site, it's perfect. For a content platform, it's not.
For our Astro development work, we use MDX even more extensively since Astro's content collections provide excellent type safety for Markdown/MDX content.
Production Metrics Comparison
Here's the data from our actual production deployments and evaluations:
| CMS | Pages in Production | Languages | Build Time | Monthly Cost | Our Verdict |
|---|---|---|---|---|---|
| Payload 3 | 228 (SleepDr) | 1 | ~45s | $35 (Payload Cloud) | Best DX for Next.js |
| Supabase | 253K (DA+NAS+HostList) | 30 | ~10s | $25 (Pro plan) | Best for scale |
| Strapi 5 | 0 (evaluated) | N/A | N/A | Free (self-hosted) | Best for GUI editors |
| Sanity | 0 (evaluated) | N/A | N/A | ~$300-500 est. | Best for collaboration |
| Contentful | 0 (evaluated) | N/A | N/A | $300+ (Basic) | Best for enterprise |
| MDX | ~60 (this site) | 1 | ~30s | $0 | Best for dev blogs |
The build time column deserves explanation. Payload at 45 seconds includes generating 228 static pages. Supabase at 10 seconds is because we don't statically generate 253K pages -- we use dynamic rendering with ISR. MDX at 30 seconds is for ~60 articles with syntax highlighting and image optimization.
Decision Framework: How to Pick Your CMS
Forget feature checklists. Answer these four questions:
1. Who's editing content?
- Only developers → MDX or Payload
- Developers + technical editors → Payload or Sanity
- Non-technical marketing team → Strapi or Contentful
2. How many pages?
- Under 500 → Any CMS works. Pick based on editor UX.
- 500-5,000 → Payload or Sanity. Both handle this range well.
- 5,000-50,000 → Supabase or Contentful (with budget).
- 50,000+ → Supabase. Nothing else makes economic sense.
3. What's your monthly CMS budget?
- $0 → Self-hosted Payload, self-hosted Strapi, or MDX
- $25-50 → Supabase Pro or Payload Cloud
- $100-500 → Sanity Growth or Strapi Cloud
- $500+ → Contentful or Sanity Enterprise
4. Do you need real-time collaboration?
- Yes, critical → Sanity (best in class)
- Nice to have → Payload (live preview is close)
- Don't care → Anything else
What We'd Do Differently
Hindsight is valuable. Here's what we'd change:
We'd have started with Payload sooner. We built some early projects with custom admin panels on top of Supabase before Payload 3 matured. For sites under 5K pages, Payload would have saved us significant admin UI development time.
We'd standardize our Supabase-as-CMS patterns earlier. Each of our three Supabase projects has slightly different conventions for content modeling, caching, and revalidation. We've since created an internal template that we use for all new high-volume projects.
We'd skip the Contentful evaluation for non-enterprise clients. The pricing cliff is real, and twice we went through multi-week evaluations only to realize the client's budget didn't match Contentful's pricing. We should have asked about budget first.
If you're facing a similar CMS decision for a Next.js project, we're happy to share more details about our experience. Check out our pricing page or get in touch directly -- we do this stuff every day.
FAQ
What is the best headless CMS for Next.js in 2026?
Based on our production experience across 253K+ pages, Payload CMS 3 is the best overall choice for Next.js App Router. Its Local API eliminates network overhead, TypeScript types are generated automatically, and the admin panel lives inside your Next.js app. For sites exceeding 10,000 pages, we recommend Supabase as a CMS layer with a custom admin interface.
Is Payload CMS really free?
Payload CMS is open-source and free to self-host with no feature restrictions. You'll need to provide your own hosting and database (MongoDB or PostgreSQL). Payload Cloud, their managed hosting service, starts at approximately $35/month for production workloads in 2026. There are no per-seat charges on the self-hosted version.
Can I use Supabase as a CMS for Next.js?
Yes, and we do it at scale. We run three production sites totaling 253,000+ pages on Supabase. It works exceptionally well when your content is structured data (profiles, listings, product catalogs) rather than long-form editorial content. The main tradeoff is that you'll need to build your own content editing interface -- Supabase's Table Editor isn't designed for editorial workflows.
How does Strapi 5 compare to Payload CMS 3 for Next.js?
Strapi 5 excels at non-technical content editing with its visual Content-Type Builder. Payload 3 excels at developer experience with its Local API and TypeScript-native approach. If your editors are developers, pick Payload. If your editors are marketers, pick Strapi. We wrote a detailed Payload vs Strapi comparison covering this topic in depth.
What's the cheapest headless CMS for Next.js?
Self-hosted Payload CMS and self-hosted Strapi are both genuinely free. MDX files in a Git repo cost nothing beyond your hosting. For managed services, Supabase Pro at $25/month offers the best value at scale -- we serve 253K pages on a single Pro plan. Sanity's free tier is also generous for small projects (up to 3 users, 500K API requests/month).
Is Contentful worth the price for Next.js projects?
Contentful is worth it if you're an enterprise team that needs a 99.99% SLA, established integrations with tools like Commercetools or Salesforce, and you have the budget ($300+/month for Basic, $3,000+/month for Premium). For startups and mid-size companies, Payload or Sanity deliver comparable functionality at a fraction of the cost.
Should I use ISR or SSR with a headless CMS in Next.js App Router?
It depends on your page count and content update frequency. For sites under 5,000 pages, static generation with on-demand revalidation via webhooks is ideal. For 5,000+ pages, dynamic rendering with ISR (revalidate = 3600 or similar) is more practical -- you can't build 50K pages on every deployment. With Payload's Local API, the distinction matters less because there's no network overhead either way.
Can I migrate from WordPress to a headless CMS for Next.js?
Absolutely. We've done multiple WordPress migrations. The typical path is: export WordPress content via REST API or WP-CLI, transform and import into your target CMS, then rebuild the frontend in Next.js. Payload CMS makes this especially smooth because you can model your collections to match your existing WordPress post types. For more details on this process, see our headless CMS development solutions.