When headless is the right call
Headless Drupal makes sense when at least two of these are true:
- You have a serious front-end team that will own the UI long-term
- The same content powers multiple surfaces (web, mobile app, kiosk, partner sites)
- You need component-level interactivity that's painful in Twig
- You want to deploy front-end changes independently of CMS changes
If you have one of these, headless is plausible. If you have none of them, you're inheriting all of the operational complexity of a two-system architecture in exchange for none of the benefit.
When it absolutely isn't
Headless is the wrong choice when editors are the primary audience of your build, when you have a single front-end target, and when the team that will maintain it doesn't include a React-fluent engineer. In those cases, Drupal with a well-built Twig theme is faster to ship, cheaper to run, and dramatically easier to debug.
The cost of a headless architecture is paid in editor experience and operational complexity. The benefit is paid in front-end freedom and content reuse. If you can't name the front-end freedom you're buying, don't pay the cost.
JSON:API vs GraphQL
Both ship as contrib in the Drupal ecosystem. We've used both in production. Defaults:
- JSON:API — pick this when your front-end consumes Drupal entities the way Drupal models them. Lower setup cost, better caching, fewer moving parts. Default for marketing sites and content-heavy front-ends.
- GraphQL — pick this when the front-end needs to compose data across many entity types per request, or when you have a single GraphQL gateway in front of multiple backends. Higher setup and ongoing cost, but the request shape is whatever the client wants.
For most projects, JSON:API is enough. We move to GraphQL when we're consciously paying for shape flexibility and we know what we're paying for.
SSR vs ISR vs static
For Next.js, the rendering decision is per route. Our defaults:
- Static (SSG) — marketing pages, blog posts, anything content-led and not personalised. Cheapest to serve, fastest to load.
- ISR (Incremental Static Regeneration) — the same content set, but where editors expect their changes to appear within minutes of publishing. Drupal triggers a webhook on node save to revalidate the specific path.
- SSR — only when the request is personalised (authenticated user, geo-targeted, A/B tested at request-time).
Editor preview without breaking your soul
This is the single biggest gotcha on a headless Drupal build. Editors are used to clicking "Preview" inside Drupal and seeing exactly what the public will see. In a decoupled architecture, the public version lives in Next.js — Drupal can't render it.
The pattern that works:
- Drupal serves a "preview" version of the unpublished node via JSON:API with an authenticated token
- Next.js exposes a
/api/previewroute that accepts that token, sets a preview cookie, and redirects to the page - The page reads the cookie, calls Next.js's
draftMode(), and fetches the unpublished revision instead of the published one - An "Exit preview" link on every page calls a Next.js endpoint that clears the cookie
Get this right early. Editors who can't preview will revolt three weeks before launch.
Authentication and content negotiation
Three patterns, picked by your security profile:
- Simple OAuth — for site-to-site authentication. Front-end has its own service-account token.
- JWT with Simple OAuth — for end-user authentication that survives across Drupal and the headless front-end.
- Cookie-based with same-domain Drupal — when the front-end and Drupal live on the same domain (front-end at
/, Drupal at/cms), shared session cookies just work. Lowest setup cost. Don't dismiss it.
Performance and caching
The performance wins of headless are real but conditional. They come from three places:
- Edge-served static HTML — Vercel, Cloudflare Pages, Netlify edge. First byte from the nearest POP, not from your Drupal origin.
- Aggressive caching of the API layer — Drupal's BigPipe and JSON:API output is cache-tag aware. Use Fastly or Varnish in front to push hit rate to 90%+.
- Front-end code splitting and image optimisation — Next.js's
next/imageis genuinely good. Use it.
Deployment topology
The four common shapes:
- Single domain, split paths — Drupal at
/cms, Next.js at/, reverse proxy stitches them. Easiest auth, easiest editor experience, hardest to do at edge. - Front-end on Vercel, Drupal on origin — most common. Drupal lives behind a load balancer, Vercel calls the JSON:API endpoint for build / ISR.
- Front-end on Cloudflare Pages — works well, has nuances around ISR.
- Self-hosted Next.js — when you have to keep everything in one environment. Less magic, more operational work.
If you're starting a headless Drupal build and want a second opinion on the architecture before you commit, get in touch. A 30-minute call is usually enough to either de-risk the next three months or steer you back to a coupled architecture and save the cost entirely.