Every Next.js project reaches the "where do we put the content?" moment. The answer depends on who's editing, how often, and how much developer control you need.
I've shipped production projects with Sanity, Payload CMS, and raw MDX files. Here's the honest tradeoff table.
The three options
Raw MDX (what this site uses)
Content lives as .mdx files in the repo. Developers edit directly. No CMS dashboard, no API, no database.
When it works:
- Developer is the only content editor
- Content changes ship with code (versioned in git)
- You want zero runtime dependencies for content
- Blog posts, documentation, portfolio pages
When it breaks:
- Non-technical editors need to publish content
- Content updates need to happen without a deploy
- You need real-time preview for editors
- Content relationships are complex (tags, categories, cross-references at scale)
Real cost: Zero. No hosting, no API calls, no subscription. Content is part of the codebase.
My experience: This site (dimaver6.com) runs on raw MDX. 40+ blog posts, 3 locales, all edited in VS Code, all versioned in git. Builds are fast because content is static. I've never needed a CMS dashboard for this use case.
Sanity
Hosted headless CMS. Content lives in Sanity's cloud. You query it via GROQ (their query language) or GraphQL.
When it works:
- Non-technical editors need a visual editing experience
- Content updates should be instant (no deploy required)
- You need real-time collaboration between editors
- Complex content models with references, arrays, rich text
- Marketing sites where content changes weekly
When it breaks:
- You're the only editor (overhead for no benefit)
- You want content versioned in git
- Budget is tight (free tier is generous, but scales up)
- You need full control over the content storage layer
Real cost: Free tier covers most small projects. Paid starts at $99/month when you exceed free tier limits. The real cost is learning GROQ and the Sanity schema DSL — budget 4–8 hours for initial setup.
My experience: Used Sanity on 3 client projects. The real-time editing experience is excellent. The downside: content is in Sanity's cloud, not your repo. If Sanity goes down or changes pricing, migration is a project.
Payload CMS
Self-hosted, open-source headless CMS. Content lives in your own database (MongoDB or Postgres). Admin UI is auto-generated from your config.
When it works:
- You want a CMS but need full data ownership
- Non-technical editors need a dashboard
- You're already running a database
- You need custom workflows, access control, or hooks
- GDPR requires data residency (your server, your region)
When it breaks:
- You don't have infrastructure to host it (Payload needs a Node.js server)
- The project is a simple blog or portfolio (overkill)
- You want managed hosting without ops work
Real cost: Free (open source). But you pay for hosting — a small VPS ($5–20/month) or your existing infrastructure. Setup time: 6–12 hours for a production-ready config with custom collections.
My experience: Used Payload on 2 client projects where the client needed to edit product data and the GDPR requirement mandated EU data residency. The admin UI is clean and customizable. The trade-off: you're now maintaining a CMS server alongside your Next.js app.
The comparison table
| Raw MDX | Sanity | Payload | |
|---|---|---|---|
| Editor | Developer only | Anyone (visual editor) | Anyone (admin UI) |
| Hosting | None (files in repo) | Sanity cloud | Self-hosted |
| Cost | Free | Free → $99+/mo | Free + hosting |
| Deploy needed for content? | Yes | No | No |
| Git versioned | Yes | No (their versioning) | No (database) |
| Data ownership | Full | Sanity's cloud | Full |
| Setup time | 1 hour | 4–8 hours | 6–12 hours |
| Best for | Dev blogs, docs, portfolios | Marketing sites, teams | Data-heavy apps, GDPR |
My decision tree
- Am I the only content editor? → Raw MDX. No contest.
- Does the client need to edit content without a developer? → CMS needed. Go to 3.
- Does the client need data residency (GDPR, compliance)? → Payload (self-hosted).
- Does the client want zero ops work? → Sanity (managed).
- Is the content model complex (50+ content types, relations)? → Payload (more flexible schema).
- Is the budget tight and the content simple? → Sanity free tier.
The hybrid pattern
For E7 Platform, we used a hybrid: event data in Postgres (managed by the app), marketing pages in MDX (managed by the developer). No CMS at all. The client edits event data through the app's admin panel — which we built anyway for operational reasons.
This "app-as-CMS" pattern works when the content that needs editing is also business data. You don't need a separate CMS for content that already has CRUD in the app.
What I'd pick for common scenarios
Personal portfolio/blog: Raw MDX. You're a developer. Edit in VS Code.
Agency marketing site (3–5 pages, updated monthly): Sanity free tier. The client can edit hero text and testimonials without calling you.
SaaS with a blog and help docs: Payload if you already run a server. Sanity if you want managed. MDX for the docs (developers write docs anyway).
E-commerce product catalog: Neither — use your e-commerce platform's built-in content tools. Shopify, Medusa, or Saleor already have product content management.
Building a Next.js project and not sure where to put the content? Let's talk — I've shipped all three approaches and can recommend the right one for your project in a single call.