Published by January 21, 2025 · Reading time 6 minutes · Created by Cod'Hash Team
After years working with different CMS platforms for our clients — WordPress, Strapi, Contentful, Sanity — one conclusion became clear: no existing solution truly addresses the needs of modern projects.
This isn't a blanket criticism. These are concrete observations from real production projects.
WordPress: A relational database used as a file system. Every plugin adds dozens of tables. Simple multilingual content becomes a nightmare with WPML, Polylang, or TranslatePress. Result? Catastrophic performance and accumulating technical debt.
Strapi: Promising on paper, but reality differs. Managing complex relationships quickly becomes hell. The permission system lacks granularity. Worst of all, the v3 to v4 migration broke so many projects that teams chose to rewrite everything from scratch.
Contentful & Sanity: Excellent for structured content, but pricing explodes with real traffic. $500/month to manage 10 company blogs? You're paying for features you don't need.
The real problem? These CMS platforms aren't designed for the specific needs of modern agencies and SaaS products.
Analyzing our last 15 client projects, clear patterns emerged:
No complex GraphQL with 50 optional fields. Our frontend teams want:
GET /api/v1/blog/articles → article listGET /api/v1/blog/articles/[slug] → specific articlePOST /api/v1/blog/articles → create articleThat's it. Clear endpoints, API key authentication, and it works. No 200-page documentation to read.
When clients ask for a FR/EN/DE blog, we don't want to:
/fr/article returns the English versionOur solution? Each article has native translations. One slug per language. SEO metadata per language. All in a clean, predictable data structure.
// Actual API structure
{
"id": "article-123",
"status": "PUBLISHED",
"translations": [
{
"language": "en",
"slug": "why-headless-cms",
"title": "Why a Headless CMS?",
"seoTitle": "Headless CMS: Our Custom Solution",
"published": true
},
{
"language": "fr",
"slug": "pourquoi-cms-headless",
"title": "Pourquoi un CMS headless ?",
"seoTitle": "CMS Headless : Notre Solution sur-mesure",
"published": true
}
]
}
Clients often want to manage multiple blogs. But with traditional CMS:
Our approach? Multi-tenant SaaS. Each organization has its blog, API keys, team, billing. One deployment. One database. One codebase.
A modern CMS must handle teams. Here's what we implemented:
Each member can have API key permissions:
blog:read — read-only accessblog:write — create/editblog:publish — publish articlesblog:manage — full managementNo rigid predefined roles. Composable permissions.
Generate an XML sitemap? It's an endpoint:
GET /api/v1/blog/sitemap.xml
RSS feed? Same logic:
GET /api/v1/blog/rss.xml
Open Graph metadata, estimated reading time, optimized images, canonical URLs — all handled natively. No need to install Yoast or equivalent.
We didn't start from scratch. We chose proven technologies:
Next.js 15 + React 19 + TypeScript
PostgreSQL + Prisma
.prisma file per feature)better-auth
Validation and Types
Documented REST API
/api/v1/blog/*)Every article view is tracked with:
Endpoint:
GET /api/v1/blog/analytics
Search across title, excerpt, and content. Filter by category, tag, status. Sort by date or popularity.
GET /api/v1/blog/search?q=headless&category=dev&sort=popular
UploadThing for uploads. Track dimensions, size, usage. Alt text for accessibility.
Create API keys with precise permissions:
{
"name": "Frontend Production",
"permissions": ["blog:read"],
"expiresAt": "2026-01-21"
}
After 6 months of development and 3 months in production:
Performance
Development
Costs
Headless is the right approach. Our clients want Next.js, Nuxt, Astro. They don't want WordPress themes.
API simplicity pays off. No complex GraphQL. Clear REST endpoints. 2-page documentation.
Native multilingual is essential. It's not a plugin. It's core to the data model.
Media management. Currently functional but basic. We're planning:
Webhooks. Currently requires polling the API. We're adding:
Content editor. Tiptap works, but we want:
We didn't create this CMS for technical ego. We built it because no existing solution met our real needs:
This CMS isn't for everyone. If you need a simple 10-page static website, WordPress will work fine.
But if you're building:
Then you'll encounter the same limitations we did. And you'll understand why we made this choice.
Want to discuss your project or learn more? Contact us.