Skip to content

blog · side by side

MDX blog vs Payload blog for a Next.js app

Both fill the blog slot, so a generated repo carries one or the other, never both. Every line below is read out of the two manifests.

Short answer

Pick MDX blog if

Engineering blogs, changelogs, docs-adjacent writing and any site where the writers already have commit access. Best when posts should go through review with the code they describe. Also when a post needs to import a real component from the app.

Pick Payload blog if

Teams who want editors in an admin UI but will not put their content in someone else's database. Strong when CMS content joins application data. Also when you need custom fields, hooks or access rules a hosted CMS will not give you. Or when data residency and export matter.

Side by side

Price, obligations, and the surface each one adds. No row is written by hand. This is manifest.yaml, rendered.

MDX blog compared with Payload blog on pricing, fit, trade-offs, required companions, environment variables, dependencies, MCP servers and repo footprint.
From the manifestOption AMDX blogOption BPayload blog
In one lineMDX blog

Posts are files in your repo. Reviewed in a pull request, shipped with the code.

Payload blog

A full CMS in your own repo and database. No second service, no content API bill.

PricingMDX blog

Free. No vendor, no seats, no API quota. The only cost is build time.

Payload blog

Free and open source (MIT). You host it, so the cost is the Postgres and Vercel functions you already pay for. Payload also sells an Enterprise plan with dedicated support and SSO. It has no public price.

Best forMDX blog

Engineering blogs, changelogs, docs-adjacent writing and any site where the writers already have commit access. Best when posts should go through review with the code they describe. Also when a post needs to import a real component from the app.

Payload blog

Teams who want editors in an admin UI but will not put their content in someone else's database. Strong when CMS content joins application data. Also when you need custom fields, hooks or access rules a hosted CMS will not give you. Or when data residency and export matter.

Trade-offsVerbatim from the manifestMDX blog
  • Publishing needs a deploy. A typo fix is a commit, a build and a rollout. Fine for engineers. Painful for a marketing team that expects a "publish" button.
  • No editor. Writers work in a code editor with YAML frontmatter and Git. The only preview link is a deploy preview, and the only permissions are repository access.
  • No image pipeline. Images live in public/, and you size and compress them. A hosted CMS gives you transforms and a CDN.
  • Content and code share a release cycle. Reverting a bad deploy reverts the posts published in it, and a content-only change still runs your whole build.
  • Everything is yours. No API keys to rotate, no dataset to lose access to, no pricing change to absorb. The whole archive greps in one command.
Payload blog
  • You operate it. Migrations, backups, upgrades and the admin bundle's build time are yours. A hosted CMS has none of that, and that is the whole trade.
  • It shares your database connection budget. The admin panel and your app draw from the same pool, so on serverless a pooled connection string is not optional.
  • Cold starts are real. The admin routes load Payload, the database driver and the editor bundle, so the first hit after idle is slow. It is an internal tool, so this is usually fine. Tell your editors before they report it as a bug.
  • Uploads need an object store before you deploy. Local disk works on your laptop and disappears on serverless. The media collection ships pointed at public/media and must be repointed.
  • Schema changes are code plus a migration. That is a feature in review and a speed bump when an editor asks for one more field.
Required companionsAdded for you, with a reasonMDX blog

Nothing. It stands on its own.

Payload blog
  • A database battery
Recommended alongsideSuggested, never added for youMDX blog

Nothing suggested.

Payload blog
  • A file storage battery
Env vars you will manageEvery one documented in docs/onboard.mdMDX blog

0 variables

None.

Payload blog

1 variable · 1 required

  • PAYLOAD_SECRET
Dependencies addedMDX blog
  • @mdx-js/loader ^3 (dev)
  • @mdx-js/react ^3
  • @next/mdx ^16
  • @types/mdx ^2 (dev)
  • gray-matter ^4.0.3
  • rehype-slug ^6
  • remark-frontmatter ^5
  • remark-gfm ^4
Payload blog
  • @payloadcms/db-postgres ^3.90.2
  • @payloadcms/next ^3.90.2
  • @payloadcms/richtext-lexical ^3.90.2
  • payload ^3.90.2
  • sharp ^0.35.4
MCP serversWritten into .mcp.jsonMDX blog

None. No extra agent tools from this one.

Payload blog

None. No extra agent tools from this one.

Footprint in your repoMDX blog

13 files, plus 3 injections into shared stack files

Payload blog

17 files, plus 5 injections into shared stack files

What changes in your repo

The paths each battery contributes, diffed. A path in the third list is written by both, so swapping rewrites that file rather than adding one.

Only with MDX blog (13)

  • content/2 files
    • blog/2 files
      • hello-world.mdx
      • writing-with-mdx.mdx
  • scripts/1 file
    • blog/1 file
      • check-posts.ts
  • src/10 files
    • app/5 files
      • blog/4 files
        • [slug]/2 files
          • opengraph-image.tsx
          • page.tsx
        • rss.xml/1 file
          • route.ts
        • page.tsx
      • sitemap.ts
    • components/2 files
      • blog/2 files
        • callout.tsx
        • post-card.tsx
    • lib/2 files
      • blog/2 files
        • frontmatter.ts
        • posts.ts
    • mdx-components.tsx

Only with Payload blog (17)

  • src/16 files
    • app/9 files
      • (frontend)/3 files
        • api/1 file
          • blog-preview/1 file
            • route.ts
        • blog/2 files
          • [slug]/1 file
            • page.tsx
          • page.tsx
      • (payload)/6 files
        • cms/3 files
          • [[...segments]]/2 files
            • not-found.tsx
            • page.tsx
          • importMap.ts
        • cms-api/2 files
          • [...slug]/1 file
            • route.ts
          • graphql/1 file
            • route.ts
        • layout.tsx
    • components/1 file
      • cms/1 file
        • rich-text.tsx
    • payload/6 files
      • collections/3 files
        • media.ts
        • posts.ts
        • users.ts
      • migrations/1 file
        • index.ts
      • access.ts
      • local.ts
  • payload.config.ts

Shared stack files MDX blog injects into

  • nav-links
  • next-config-wrappers
  • verify-checks

Shared stack files Payload blog injects into

  • bare-route-groups
  • env-required
  • nav-links
  • next-config-wrappers
  • verify-checks

MDX blog in your .env.local

.env.localbash1 line
# MDX blog adds no environment variables.

Payload blog in your .env.local

.env.localbash2 lines
# required
PAYLOAD_SECRET=replace-with-32-random-characters

What changes for your agents

Each battery ships rules, skills, subagents and hooks that an agent loads before it touches the code that battery owns. Picking one is also picking how your agents behave in content/**.

MDX blog

  • 2

    Skills

  • 2

    Rules

  • 5

    Solution docs

Rules (2)

Posts are validated content, not free-form files

content/**

The blog compiles at build time and styles itself with tokens

src/app/blog/** · src/app/sitemap.ts · src/lib/blog/** · src/components/blog/** · src/mdx-components.tsx

Skills (2)

/add-mdx-component

Add a component that posts can use without importing it, registered in src/mdx-components.tsx and styled with design tokens only.

/new-post

Draft, validate and publish a new MDX post in content/blog, with frontmatter that passes the checker and a slug that will never change.

Subagents and hooks

None of its own. The foundation agents and guard hooks still ship.

Payload blog

  • 2

    Skills

  • 2

    Rules

  • 5

    Solution docs

Rules (2)

Read Payload through the local API, never over HTTP

src/app/(frontend)/** · src/app/(payload)/** · src/payload/local.ts · src/components/cms/**

Collections are code, and every change ships with a migration

payload.config.ts · src/payload/**

Skills (2)

/add-collection

Add a Payload collection end to end: fields, explicit access control, migration, regenerated types and the page that renders it.

/payload-migrate

Create, review, apply and deploy Payload migrations safely, including renames, backfills and what to do when a migration fails halfway.

Subagents and hooks

None of its own. The foundation agents and guard hooks still ship.

What each one already knows

Solution docs land in docs/solutions/ in your repo and are published here, so you can read the failure modes before you commit.

MDX blog (5)

Payload blog (5)

Which one to pick

From meta.bestFor and meta.tradeoffs. If a claim is not in the manifest, it is not on this page.

Pick MDX blog when

Engineering blogs, changelogs, docs-adjacent writing and any site where the writers already have commit access. Best when posts should go through review with the code they describe. Also when a post needs to import a real component from the app.

And accept that(5)
  • Publishing needs a deploy. A typo fix is a commit, a build and a rollout. Fine for engineers. Painful for a marketing team that expects a "publish" button.
  • No editor. Writers work in a code editor with YAML frontmatter and Git. The only preview link is a deploy preview, and the only permissions are repository access.
  • No image pipeline. Images live in public/, and you size and compress them. A hosted CMS gives you transforms and a CDN.
  • Content and code share a release cycle. Reverting a bad deploy reverts the posts published in it, and a content-only change still runs your whole build.
  • Everything is yours. No API keys to rotate, no dataset to lose access to, no pricing change to absorb. The whole archive greps in one command.

Pick Payload blog when

Teams who want editors in an admin UI but will not put their content in someone else's database. Strong when CMS content joins application data. Also when you need custom fields, hooks or access rules a hosted CMS will not give you. Or when data residency and export matter.

And accept that(5)
  • You operate it. Migrations, backups, upgrades and the admin bundle's build time are yours. A hosted CMS has none of that, and that is the whole trade.
  • It shares your database connection budget. The admin panel and your app draw from the same pool, so on serverless a pooled connection string is not optional.
  • Cold starts are real. The admin routes load Payload, the database driver and the editor bundle, so the first hit after idle is slow. It is an internal tool, so this is usually fine. Tell your editors before they report it as a bug.
  • Uploads need an object store before you deploy. Local disk works on your laptop and disappears on serverless. The media collection ships pointed at public/media and must be repointed.
  • Schema changes are code plus a migration. That is a feature in review and a speed bump when an editor asks for one more field.

Questions people actually ask

Should I choose MDX blog or Payload blog?
MDX blog is best for engineering blogs, changelogs, docs-adjacent writing and any site where the writers already have commit access. Best when posts should go through review with the code they describe. Also when a post needs to import a real component from the app. Payload blog is best for teams who want editors in an admin UI but will not put their content in someone else's database. Strong when CMS content joins application data. Also when you need custom fields, hooks or access rules a hosted CMS will not give you. Or when data residency and export matter. Both fill the blog slot, so a generated repo carries one or the other, never both.
How much do MDX blog and Payload blog cost?
MDX blog: Free. No vendor, no seats, no API quota. The only cost is build time. Payload blog: Free and open source (MIT). You host it, so the cost is the Postgres and Vercel functions you already pay for. Payload also sells an Enterprise plan with dedicated support and SSO. It has no public price.
What changes in my repo if I switch from MDX blog to Payload blog?
MDX blog writes 13 files, 0 environment variables and 8 dependencies, and installs 2 path-scoped rules, 2 skills and 5 solution docs. Payload blog writes 17 files, 1 environment variable and 5 dependencies, and installs 2 path-scoped rules, 2 skills and 5 solution docs.

Decide once, then build the repo that already knows the decision.

Either way you get that choice’s rules, skills and solution docs installed, plus the guard hooks, an onboarding doc for exactly these env vars, and the Compound Engineering loop. Free and MIT.