Headless CMS for Next.js: How to Choose in 2026

SaaS vs self-hosted, a real comparison, and the webhook loop the listicles skip

June 22, 2026 · 10 min read
Headless CMS for Next.js: How to Choose in 2026

Pick a headless CMS for Next.js and you're really picking two things at once: where your content lives, and how it gets to the browser. Most "best CMS for Next.js" lists skip the second part — the wiring — and that's the part that bites you in week three.

This guide compares the headless CMS options developers actually reach for with Next.js in 2026, then shows the one thing the listicles leave out: the real publish-to-rebuild loop that keeps a statically-generated site fresh.

TL;DR: For visual editing and marketing teams, Sanity and Storyblok lead. For TypeScript-first, code-as-config setups, Payload wins. If you want to own your data and host it yourself, a Laravel-backed option like UnfoldCMS fits — it talks to Next.js over a plain REST API and fires a webhook on publish so Next.js can revalidate on demand. The right pick depends on one question: SaaS convenience, or self-hosted control?

What "headless CMS for Next.js" actually means

A headless CMS for Next.js is a content back end with no front end of its own. Your editors write content in the CMS; Next.js fetches that content over an API (REST or GraphQL) and renders the pages. The "head" — the part users see — is your Next.js app, fully decoupled from where the content is stored.

That split is the whole point. Your front end can be statically generated, server-rendered, or a mix, hosted on Vercel, Netlify, or Cloudflare. The CMS doesn't care. It just serves JSON.

The trade-off: you now own the glue. Fetching, caching, and revalidation — telling Next.js "this content changed, rebuild it" — are your job. Pick a CMS that makes that glue easy, and the rest is smooth.

What to look for in a headless CMS for Next.js

Before comparing names, get clear on the criteria. Not every CMS scores well on all of these, and the ones that matter depend on your team.

  • API quality — REST, GraphQL, or both? Clean pagination, filtering, and a predictable response shape save you days.
  • Revalidation support — does the CMS fire a webhook on publish? Without it, you're stuck with time-based rebuilds (ISR) and stale content windows.
  • Pricing model — flat (self-hosted) vs per-seat or per-API-call (SaaS). This is where costs surprise teams at scale.
  • TypeScript story — is there an official SDK with generated types, or do you type the responses yourself?
  • Self-host vs SaaS — who runs the server, who owns the data, and what happens if the vendor changes pricing.
  • Editor experience — your writers live in this UI every day. A bad admin kills adoption faster than a bad API.

A quick way to choose: if your bottleneck is editor happiness, weight the last two. If it's developer control and cost, weight the first four.

The leading headless CMS options compared

Here's how the common Next.js choices stack up. The question most teams are really asking: which of these fits my stack and budget without locking me in?

CMS Type Backend stack API Pricing model On-publish revalidation Official SDK
Sanity SaaS Node / GROQ GROQ + GraphQL Per-seat + usage Webhooks Yes (next-sanity)
Contentful SaaS Proprietary REST + GraphQL Per-seat + API calls Webhooks Yes
Payload Self-host or SaaS Node + Mongo/Postgres REST + GraphQL Flat (self-host) / usage Hooks Yes (TS-native)
Storyblok SaaS Proprietary REST + GraphQL Per-seat + usage Webhooks Yes
UnfoldCMS Self-host PHP / Laravel REST (/api/v1) Flat (own the server) Signed webhooks No — plain fetch()

A note on that last row, because it's the honest part: UnfoldCMS has no official npm SDK. No @unfoldcms/react, no generated types out of the box. You call the REST endpoints with plain fetch(). For some teams that's a downside. For others it's the point — no SDK means no version-lock to a vendor package, and the API surface is small enough to wrap in a 30-line typed helper of your own.

Sanity and Storyblok shine for visual editing. Payload is the pick if you want your CMS config to live in your repo as TypeScript. The self-hosted Laravel option trades the polished SDK for full data ownership and a flat cost — you run it on your own VPS, and nobody can change your pricing.

How to connect a headless CMS to Next.js (the real workflow)

This is the section the comparison posts skip. Fetching content is easy. Keeping a statically-generated site fresh when an editor hits publish is the part that takes real wiring. Here's the full loop, using a REST CMS as the example.

Step 1 — Fetch content in a Server Component. With the App Router, you fetch directly in the component. No getStaticProps.

// app/blog/[slug]/page.tsx
async function getPost(slug: string) {
  const res = await fetch(`https://cms.example.com/api/v1/posts/${slug}`, {
    next: { tags: [`post:${slug}`] }, // tag for on-demand revalidation
  });
  if (!res.ok) return null;
  const { data } = await res.json();
  return data;
}

export default async function PostPage({ params }: { params: { slug: string } }) {
  const post = await getPost(params.slug);
  if (!post) notFound();
  return <article dangerouslySetInnerHTML={{ __html: post.body_html }} />;
}

Step 2 — Build an API route that revalidates. This is the endpoint your CMS will call.

// app/api/revalidate/route.ts
import { revalidateTag } from 'next/cache';
import { NextRequest, NextResponse } from 'next/server';

export async function POST(req: NextRequest) {
  const secret = req.headers.get('x-webhook-secret');
  if (secret !== process.env.CMS_WEBHOOK_SECRET) {
    return NextResponse.json({ ok: false }, { status: 401 });
  }
  const { slug } = await req.json();
  revalidateTag(`post:${slug}`);
  return NextResponse.json({ ok: true, revalidated: slug });
}

Step 3 — Point the CMS webhook at that route. In a self-hosted CMS like UnfoldCMS, outgoing webhooks are managed from the admin API (/api/v1/admin/webhooks). You register a subscriber, and on every post publish/update/delete the CMS fires a signed POST to your URL. The signature (HMAC) is what your secret check above verifies.

The loop, end to end:

  1. Editor hits publish in the CMS.
  2. CMS fires a signed webhook → your Next.js /api/revalidate route.
  3. The route calls revalidateTag() for that post.
  4. Next request to that page rebuilds with fresh content — no full redeploy, no waiting for a timed ISR window.

That's the difference between "my blog updates within an hour" and "my blog updates the second I publish." Most SaaS options support this through webhooks too; the self-hosted version just means the webhook config lives on a server you control.

SaaS vs self-hosted: cost and control

The real fork in this decision isn't which logo you pick — it's SaaS or self-hosted. They fail in opposite directions.

SaaS (Sanity, Contentful, Storyblok) gives you zero ops. No server to patch, no database to back up, a polished editor on day one. The cost shows up later: per-seat billing as your team grows, API-call limits on busy sites, and pricing that's set by the vendor, not you. Your content also lives on their infrastructure.

Self-hosted (Payload, UnfoldCMS) flips it. You run the server, so you patch it and back it up — that's real work. In return you get a flat cost (a VPS, not a per-seat invoice), and you own your data outright, which matters for GDPR and for teams that can't put content on third-party servers. No vendor can change your bill or deprecate your plan.

Rule of thumb: pick SaaS when ops time is your scarcest resource. Pick self-hosted when budget predictability and data ownership matter more than skipping server maintenance. If you're weighing this seriously, our self-hosted CMS vs managed breakdown runs the 5-year numbers.

Common mistakes when pairing a CMS with Next.js

These are the ones that show up in GitHub issues and "why is my site stale" threads, over and over.

  1. No on-demand revalidation. Relying only on time-based ISR means content can be stale for minutes or hours. Wire up the webhook → revalidateTag() loop above.
  2. Over-fetching. Pulling the whole post list on every page when you need one post. Use the single-item endpoint and cache tags.
  3. Hardcoding tokens client-side. Auth tokens belong in Server Components and route handlers, never shipped to the browser.
  4. Picking a CMS with no webhook support. If it can't tell your front end "content changed," you're stuck rebuilding on a timer forever. Check this before you commit.
  5. Skipping the typed wrapper. Even without an official SDK, write one small typed fetch helper. It catches shape changes at compile time instead of in production.

Frequently asked questions

Can I use a PHP CMS with Next.js? Yes. Next.js doesn't care what language the CMS is written in — it only consumes the API. A Laravel-based CMS like UnfoldCMS exposes a REST API at /api/v1, and Next.js fetches from it exactly like any other headless source. The back-end language is invisible to the front end.

Does headless mean I always get an SDK? No. An SDK is a convenience, not a requirement. Plenty of headless setups use plain fetch() against a REST endpoint. No SDK means a bit more typing work up front, but also no dependency on a vendor's npm package and its release cycle.

How does Next.js know when my content changes? Through a webhook. The CMS fires an HTTP request to a Next.js API route on publish, and that route calls revalidateTag() or revalidatePath() to rebuild the affected pages. Without a webhook, you're limited to time-based ISR.

Is self-hosted really cheaper? Often, at scale. SaaS pricing grows with seats and API usage; a self-hosted CMS runs at the flat cost of a VPS regardless of team size. The catch is ops time — you maintain the server. For small teams with steady traffic, self-hosting usually wins on total cost.

REST or GraphQL for a Next.js front end? Both work. GraphQL shines when you need to fetch deeply nested, varied data in one request. REST is simpler and easier to cache at the HTTP layer, which pairs naturally with Next.js cache tags. For a content site, a clean REST API is usually plenty.

So which one should you pick?

Start with the SaaS-vs-self-hosted question, because it decides most of the rest. Want a polished editor and zero server maintenance, and you're fine with usage-based billing? Go SaaS — Sanity or Storyblok for visual teams, Payload if you want config-as-code with managed hosting.

Want to own your content, run it on your own box, and keep a flat bill? A self-hosted Laravel CMS fits. UnfoldCMS gives you a REST /api/v1 surface, signed webhooks for on-demand revalidation, and no per-seat invoice — at the cost of an official SDK you'd have to replace with a small fetch wrapper.

If you're going the self-hosted route with Next.js specifically, our Next.js integration guide walks through the wiring end to end, and the how to choose a headless CMS checklist covers the decision criteria in more depth. New to the model entirely? Start with what is a headless CMS.

See the UnfoldCMS API docs → Run the /api/v1 endpoints against your own Next.js app. Self-hosted, flat cost, your data on your server.

Sources: Next.js on-demand revalidation docs, Prismic and FocusReactive 2026 Next.js CMS comparisons, and the live UnfoldCMS /api/v1 route surface. UnfoldCMS capabilities verified against the production API (June 2026). Written by Hamed Pakdaman, who builds UnfoldCMS — disclosure: this post is published on the UnfoldCMS blog.

Free & Open Source

Own your CMS. No subscriptions.

Unfold CMS is free to download and self-host. Built on Laravel + React, full source code included.

Share this post:

Discussion

Comments (0)

Leave a Comment

Please log in to leave a comment.

Don't have an account? Register here

No comments yet. Be the first to share your thoughts!

Keep Reading

Related Posts

Back to all posts
Powered by UnfoldCMS