TYPO3 as a GraphQL backend for React and Next.js

Which extensions are maintained, when GraphQL is the better API, and how to choose

I first wrote this page in 2019, when a TYPO3 initiative set out to generate a GraphQL schema from the TCA. That work stopped the same year. The repositories are still online, the last commit dates from December 2019, and no release ever reached Packagist. If you landed here looking for TYPO3-Initiatives/graphql: do not build on it.

The need did not go away. A React or Next.js frontend that lists job postings, events or products wants exactly the fields it asks for, with filters and pagination, in one request. Three maintained extensions cover that today. This page compares them, says when I would reach for GraphQL at all, and how it fits next to the page JSON a headless site already has.

Status checked in October 2026 against TYPO3 13.4 and 14.

Two shapes of data, two APIs

Most TYPO3 sites do not need GraphQL. A classic Fluid site needs no API at all, and a headless site is usually served well by EXT:headless: one request per URL returns the page with its content elements as JSON, and the frontend renders it. That is how this site works, and it is what my headless how-to describes.

Page JSON is page-shaped. It answers "what is on this URL". GraphQL is record-shaped. It answers "give me these records, these fields, filtered like this". Three signs tell me a project has record-shaped needs:

  • The frontend filters on its own. A job board, an event calendar, a directory of experts or products: the user combines location, category and date, and the list has to respond at once. One request should return the filtered list and the remaining filter options with their counts.
  • Several consumers, different field needs. Website, app and a partner widget read the same records, but each renders different fields. With GraphQL each client asks for exactly what it shows. With fixed JSON you maintain either one oversized endpoint or several.
  • Deep relations in lists. An expert with disciplines with institutions, in a list of a hundred entries. Hand-written endpoints get slow here; a GraphQL layer that batches relations does not.

The two APIs combine well, and that is the usual setup: pages, navigation and content elements through EXT:headless, record collections through a GraphQL endpoint on the same TYPO3. Replacing page JSON entirely only makes sense when the site is a data portal at its core and editorial pages play a minor role.

Three maintained extensions

itx/typo3-graphql builds the schema from Extbase models. A GraphQL.yaml in your site package lists the models to expose, and an @Expose annotation marks each public field. Relations resolve automatically. The extension generates links and image URLs and ships a filter and facet API with discrete, range and date filters. Version 4 supports TYPO3 13.4 and 14. It is the most installed of the three and the most actively released. The README still carries a warning that it is not feature complete, and lists language overlays as unfinished.

digicademy/typograph is schema-first. You write the schema as .graphql files and map each type to a database table in the site configuration. Relations are declared explicitly, including MM tables. Related records are batch-loaded, so a list with relations costs one query per relation type instead of one per row. It offers cursor pagination, sorting, field transforms for TYPO3 links, and custom resolvers for aggregates. It supports TYPO3 12.4 to 14 and handles queries only, no mutations. It is young: the first release dates from late 2025, built at the Academy of Sciences and Literature in Mainz for a research portal.

rozbehsharahi/graphql3 is code-first. You register a schema with builders on top of webonyx/graphql-php, and a built-in query type already covers pages, content and languages from the TCA. It is the only one of the three with an access-control layer: JWT tokens, mapped to frontend user groups, checked by voters. It also has an extension point for mutations. It supports TYPO3 12.4 and 13.4. There is no release for TYPO3 14, and the author states openly that the project has little movement and few real-world users.

All three are built on webonyx/graphql-php and serve the endpoint at /graphql.

How I would choose

  • Extbase models exist and the frontend needs filters or facets: itx/typo3-graphql. The facet API returns option counts and disables impossible combinations, which is most of what a filter UI needs.
  • You want to own the schema, or the data is not modelled in Extbase: TypoGraph. The schema file is the contract, the mapping stays in configuration, and the batch loading keeps relation-heavy lists cheap.
  • Records are restricted to user groups, or the client must write data: graphql3 has the building blocks. Weigh that against the missing TYPO3 14 release.
  • None of the above, you only need page content: stay with EXT:headless.

Two limits apply to all three. GraphQL is not a search: facets over a few thousand records work, typo tolerance and relevance ranking over a large corpus stay with a search engine. And none of the three has the adoption of EXT:headless. Plan for reading the extension's source, and pin the version.

The React side, in short

In a Next.js App Router project a record list is a server component, and a server component needs no GraphQL client library. A plain fetch against /graphql with a cache tag is enough. The tag is the important part: when an editor changes a record, TYPO3 calls the revalidation endpoint and Next.js drops exactly that data. The mechanism is the same one I describe in the on-demand revalidation how-to.

Apollo Client earns its place on the interactive side: a filter UI in a client component, where the normalized cache keeps list and facets consistent while the user toggles options. Apollo Client 4 works with React 19, and the separate package @apollo/client-integration-nextjs connects it to the App Router. For a page that only renders a list, it is weight without benefit.

What to lock down

A GraphQL endpoint is a public API. Before it goes live I check five things:

  1. Exposure is opt-in. Every field you annotate or map is public. Expose slim view models, not your full domain models.
  2. Introspection is off in production. itx/typo3-graphql disables it outside the development context by default.
  3. Query cost is limited. Nested relations multiply. Set a maximum query complexity.
  4. CORS is an allowlist, not a wildcard.
  5. Restricted records stay restricted. Test hidden records, start and end times and frontend user groups against the endpoint yourself. Do not assume the API applies the same rules as page rendering.

Where this fits

If the filter question is really a search question, typo tolerance and relevance ranking across a large corpus, a search engine is the better tool, and I describe that setup under Elasticsearch for TYPO3. For facets over a few thousand records, the database-backed filter API is enough and saves an entire service.

A typed schema has one more consumer today. An AI agent that should query records needs the same things a frontend needs: named operations, typed arguments, predictable results. How this site exposes its tools to agents is described in the WebMCP how-to.

Kontakt

Klingt nach Ihrem Projekt?

Sprechen wir unverbindlich darüber.

Antwort innerhalb 24h — in der Regel deutlich schneller.