The headless CMS market is crowded. Sanity, Contentful, Strapi, Payload, Directus, Hygraph, Builder.io - the list keeps growing.
After implementing dozens of CMS projects, here's how to actually choose.
The Decision Framework
Before comparing features, answer these questions:
- Who's editing content? Technical team or marketing/content folks?
- How complex is your content model? Blog posts or interconnected product data?
- What's your budget? Free tier limits or enterprise pricing?
- Self-hosted or managed? Control vs convenience trade-off
- How important is the editing experience? Real-time preview? Visual builder?
Your answers narrow the field significantly.
The Contenders
Sanity
Best for: Complex content models, real-time collaboration, developer flexibility
Pricing: Generous free tier (10K documents, 500K API requests/month). Growth plans start around $99/month.
Standout features:
- GROQ query language - incredibly powerful
- Real-time collaborative editing
- Portable Text for rich content
- Customisable Studio (React-based)
// Sanity schema example
export default {
name: 'product',
type: 'document',
fields: [
{ name: 'title', type: 'string' },
{ name: 'slug', type: 'slug', options: { source: 'title' } },
{ name: 'description', type: 'portableText' },
{ name: 'price', type: 'number' },
{
name: 'categories',
type: 'array',
of: [{ type: 'reference', to: [{ type: 'category' }] }]
}
]
}
Downsides: Learning curve for GROQ. Studio customisation requires React knowledge.
Contentful
Best for: Enterprise teams, established workflows, extensive integrations
Pricing: Free tier limited (25K records). Paid plans from $300/month - expensive.
Standout features:
- Mature platform, battle-tested
- Excellent internationalisation
- Rich integration ecosystem
- Good for large editorial teams
Downsides: Pricing scales quickly. Less flexible than Sanity for custom fields.
Strapi
Best for: Developers who want full control, self-hosted preference, budget-conscious projects
Pricing: Free and open source. Cloud hosting from $29/month.
Standout features:
- Self-hostable (you own your data)
- Auto-generated REST and GraphQL APIs
- Plugin system for extensibility
- Content types built in admin UI
// Strapi content type (created via admin or code)
// api/product/content-types/product/schema.json
{
"kind": "collectionType",
"attributes": {
"title": { "type": "string", "required": true },
"description": { "type": "richtext" },
"price": { "type": "decimal" },
"images": { "type": "media", "multiple": true }
}
}
Downsides: Self-hosting means you manage infrastructure. Less polished editing experience than hosted options.
Payload CMS
Best for: Developers who want code-first config, TypeScript projects, full ownership
Pricing: Free and open source. Cloud coming.
Standout features:
- 100% TypeScript, code-first
- Built-in authentication and access control
- Excellent developer experience
- Growing rapidly
// Payload collection config
import { CollectionConfig } from 'payload/types';
const Products: CollectionConfig = {
slug: 'products',
admin: { useAsTitle: 'title' },
access: {
read: () => true,
create: ({ req }) => req.user?.role === 'admin'
},
fields: [
{ name: 'title', type: 'text', required: true },
{ name: 'price', type: 'number' },
{ name: 'description', type: 'richText' },
{
name: 'category',
type: 'relationship',
relationTo: 'categories'
}
]
};
Downsides: Younger ecosystem. Self-hosted only (for now). Smaller community than Strapi.
Builder.io
Best for: Visual editing, marketing teams, non-technical content creators
Pricing: Free tier available. Paid from $19/month.
Standout features:
- Visual drag-and-drop builder
- Integrates with existing React/Next.js components
- A/B testing built-in
- No developer bottleneck for landing pages
Downsides: Less suitable for structured data. Best for visual content, not complex data models.
Quick Comparison Table
| CMS | Self-Hosted | Visual Editor | Free Tier | Best For |
|---|---|---|---|---|
| Sanity | No | Studio (customisable) | Generous | Complex content, developers |
| Contentful | No | Yes | Limited | Enterprise, large teams |
| Strapi | Yes | Admin UI | Unlimited | Budget, full control |
| Payload | Yes | Admin UI | Unlimited | TypeScript projects |
| Builder.io | No | Visual builder | Yes | Marketing pages |
Integration with Next.js
All modern headless CMSs work with Next.js. Here's the typical pattern:
// lib/cms.js - Sanity example
import { createClient } from '@sanity/client';const client = createClient({
projectId: process.env.SANITY_PROJECT_ID,
dataset: 'production',
apiVersion: '2024-01-01',
useCdn: true
});
export async function getProducts() {
return client.fetch(`*[_type == "product"] {
_id,
title,
"slug": slug.current,
price,
"imageUrl": image.asset->url
}`);
}
// app/products/page.jsx
export default async function ProductsPage() {
const products = await getProducts();
return (
<div>
{products.map(product => (
<ProductCard key={product._id} {...product} />
))}
</div>
);
}
Preview and Draft Mode
Most CMSs support draft previews. Here's the pattern:
// app/api/preview/route.js
import { draftMode } from 'next/headers';
import { redirect } from 'next/navigation';
export async function GET(request) {
const { searchParams } = new URL(request.url);
const secret = searchParams.get('secret');
const slug = searchParams.get('slug');
if (secret !== process.env.PREVIEW_SECRET) {
return new Response('Invalid token', { status: 401 });
}
draftMode().enable();
redirect(`/products/${slug}`);
}
// In your data fetching
export async function getProduct(slug, preview = false) {
const query = preview
? `*[_type == "product" && slug.current == $slug][0]` // Include drafts
: `*[_type == "product" && slug.current == $slug && !(_id in path("drafts.**"))][0]`;
return client.fetch(query, { slug });
}
My Recommendations
Just starting out? Go with Sanity. The free tier is generous, and it scales well.
Need full control? Strapi or Payload, self-hosted. You own everything.
Marketing-heavy site? Builder.io for landing pages, combined with Sanity for structured content.
Enterprise with budget? Contentful - mature, well-supported, integrates with everything.
TypeScript purist? Payload. Best developer experience in the code-first space.
The Real Answer
The "best" CMS is the one your content editors will actually use.
Involve them in the decision. Let them try the editing experience. A technically superior CMS is worthless if your marketing team hates using it.
We've implemented headless CMS solutions for hotels, e-commerce, and content-heavy sites at LogicLeap. Happy to help you choose the right one.
Top comments (2)
Directus mentioned at the top, but not in the contender list? 🤔ðŸ˜
Anything we can do to rank in the contenders, in your opinion?
Based on your boxes -
Self-Hosted ✅
Visual Editor ✅
Free Tier Unlimited + all features for orgs under $5m annual revenue/funding (license required for above)
Best For CMS+, meaning your website + more since it is essentially a BaaS with an automation builder, visualizations, and advanced RBAC.
So just curious how we could get better! Thank you!
Solid list, you covered the main camps! One worth adding on the open-source side, next to Strapi/Payload/Directus, is MDCMS.
It's open-source, self-hosted, no vendor lock-in. What sets it apart in that group is the fact that it's Markdown-first, content lives as .md/.mdx files, and you define the schema in code, with a visual Studio for marketers
The real differentiator is the AI workflow. Because content is stored as local files, you pull it, run any model you want on it, and push it back, so AI works directly on your content instead of through a vendor's built-in assistant.