Skip to content

ConceptFor front-end developers, module developersDrupal 11

Choose your front end

Drupal serves structured content to any front end. Drupal can render the pages itself, or your own JavaScript app can render them from the same content, and with Canvas Headless, editors keep the same visual page building either way. This page compares the three architectures so you choose one before you write code.

A Drupal site can deliver its content in three ways:

  • Drupal-rendered (coupled). Drupal handles the whole request: routing, access, render arrays, Twig templates, caching, and the final HTML. This is the default architecture and the one the rest of these docs assume; the theming section covers it.
  • Progressively decoupled. Drupal still renders the pages, but specific components on those pages are JavaScript applications that fetch data from Drupal’s HTTP API. A booking widget, a live search, a configurator. You keep the render pipeline and add interactivity only where it pays.
  • Fully decoupled (headless). Drupal never produces visitor-facing HTML. A separate application (Next.js, SvelteKit, a native app) consumes Drupal’s HTTP API and owns the entire front end. Drupal’s job narrows to content modeling, editing, access control, and serving content. On Drupal CMS, Canvas Headless keeps the editor in the loop: editors compose pages in Canvas from your app’s components and preview drafts rendered by your app.

The API side of this decision is the cheap part. Core ships the JSON:API module: install it and every content entity type on the site is readable over HTTP, with filtering, sorting, pagination, and relationship traversal, before you write any code. The module is read-only by default and exposes nothing a visitor could not already see, because every response respects entity access.

Teams go headless when the front end is where they want to invest: a front-end team that already works in React, Vue, or Svelte, one content repository feeding a website, a mobile app, and a kiosk, or interaction-heavy products where a JavaScript framework fits better than Twig.

Decoupling does not remove work. It moves it.

On a Drupal-rendered site, a request flows through routing, access checks, controllers, render arrays, Twig, and the cache layers, and HTML comes out. The render pipeline is doing an enormous amount of silent work in that flow. On a decoupled site, the pipeline is cut after the entity layer: serialization replaces theming, and everything the theme layer and render pipeline did for free becomes your front end’s responsibility. Canvas Headless hands much of it back: it resolves paths, returns page metadata, delivers editor-composed pages as component trees, and runs draft preview.

Enumerate that “everything” honestly, because each item is now a feature you build, buy, or drop:

  • URL handling. Drupal knows that /about-us is node 12 (Drupal’s term for a content item). Your front end receives a path from the browser and core’s JSON:API offers no endpoint to resolve it to an entity; you address content by UUID (the stable universally-unique identifier Drupal assigns each entity, distinct from its path). Canvas Headless resolves paths for you, including redirects and translations. With plain JSON:API, path resolution needs the contrib module Decoupled Router or a convention of your own.
  • Menus. Rendered menu HTML is gone. Core ships a replacement, the Linkset endpoint (below), but you reassemble the markup yourself.
  • Previews. An editor on a coupled site sees the page exactly as visitors will. Core has no decoupled preview. On Drupal CMS, Canvas Headless provides it: editors build pages in Canvas and preview drafts rendered by your front end. Without it, draft preview is an integration you design and build.
  • Caching. Page cache and dynamic page cache still accelerate the API responses, but the assembled-page caching, including BigPipe streaming, applies only to Drupal-rendered HTML. Your front end brings its own caching story.
  • Layout and display tools. View modes, field formatters, blocks, and layout configuration produce render arrays. A JSON:API front end reads raw field values instead, so display logic written in the admin UI stops reaching the visitor. With Canvas Headless, pages and content templates that editors build in Canvas reach your app as component trees.
  • Forms, search pages, comments, contact pages. Each is a Drupal-rendered feature you reimplement against the API.

The decision rule that falls out of this model:

  • Your team builds in a JavaScript framework, or several front ends share the content: go headless with Drupal CMS and Canvas Headless. Editors keep page building and preview, and your app owns the markup.
  • Your team builds in Twig and PHP: render with Drupal. Editors use the same Canvas editor, and the theming section covers the front end.
  • A Drupal-rendered site needs a few app-like components: decouple those components only.
  • No editor composes pages in the front end (a native app, a kiosk, an integration): read content over JSON:API directly, without Canvas.

Core itself ships the decoupled building blocks, so you can read their source:

  • JSON:API. The module registers routes for every resource type through a route subscriber and serves them all from one controller, the jsonapi.entity_resource service. There is no configuration; the API mirrors your content model automatically. Its design is documented in the JSON:API architecture topic. JSON:API basics covers consuming it. It is not the only content-model API: core also ships the older REST module, where you configure each resource, format, and method by hand, and contrib offers GraphQL, where clients compose their own queries, worth its setup and schema maintenance mainly when your team already runs a GraphQL stack. These docs standardize on JSON:API because it is core, zero-configuration, and pinned to a public specification.
  • The Linkset endpoint. The system module’s LinksetController serializes any menu tree as application/linkset+json at /system/menu/{menu}/linkset, in the RFC 9264 linkset format with a hierarchy member for rebuilding the tree client side. Each link is access-checked, so anonymous consumers see what anonymous visitors would see. The endpoint is off by default behind the linkset_endpoint flag in system.feature_flags; enable it at Administer → Configuration → Web services → Linkset API settings/admin/config/services/linkset.
  • Authentication providers. Core ships exactly two: the session cookie provider from the user module and HTTP Basic from the basic_auth module. JSON:API routes accept every enabled provider. Authentication and CORS covers the choice, including where contrib OAuth2 fits.
  • The admin UI stays coupled. Even on a fully decoupled site, editors keep using Drupal-rendered node forms, the media library, and Views listings under the Claro theme. Core does not decouple its own back office, which is also a hint about where Drupal-rendered HTML remains the right tool.
  • “Headless means giving up the editor experience.” With Canvas Headless, editors compose pages in Canvas from your app’s components and preview drafts rendered by your app. What stays yours is the front end itself: hosting, caching, forms, and search.
  • “Exposing an API requires setup.” The JSON:API module is core, zero-configuration, and read-only by default. The expensive part of headless was never the API; it is rebuilding the front-of-site features listed above.
  • “Decoupling makes the site faster.” It makes the API fast to consume and the rendering your problem. A well-cached Drupal-rendered page is one cached HTTP response; a decoupled page is your front end’s caching discipline plus API round trips. Decoupled sites can be very fast, but by your effort, not by default.
  • “Editors keep their preview button.” Preview of unsaved or draft content does not survive decoupling on its own. Plan the preview integration during architecture, not after editors complain. Canvas Headless is the Drupal counterpart to front-end draft modes; core does not provide one.
  • “Path aliases keep working with JSON:API.” Your front end gets /about-us from the browser, and core JSON:API has no endpoint to turn it into content. Canvas Headless resolves paths with fetchPage(). Without it, decide early how URLs map to entities: the Decoupled Router contrib module, route files in the front end, or storing paths at build time.
  • “Headless removes PHP development.” The Drupal side still needs content modeling, access logic, custom API additions, and event subscribers. Decoupled projects typically need more back-end discipline, not less, because the API contract is now a public interface.

Was this page helpful?

Drupal is a registered trademark of Dries Buytaert.