Customizing the Drupal JSON:API with JSON:API Extras: when a headless build needs it
A headless build needs JSON:API Extras when the public shape of its API should not change every time the content model does. Drupal core generates its JSON:API from the entity types, bundles and fields that exist on the site, so a Next.js or mobile front end that calls the default paths is consuming the internal names of content types and fields. Adding a field, renaming a content type machine name or changing a field's type can change what consumers receive. The contributed JSON:API Extras module exists to put a layer between those internal names and the API that clients see. Its documentation describes renaming resources and fields, disabling resources and fields that consumers do not need, and changing the path prefix under which the API is served. Confirm the exact settings and the module version you will run against the project page before you design around them, because the options available depend on the Drupal core version in use.
Before you configure anything, decide which consumers you must protect and how often the content model will change. A team with one front end that its own developers control can often rename fields in the same release as the front end change. A team with several front ends, a mobile app that users update on their own schedule, or partners who read the API will need a stable contract that outlives individual model changes. Shaping the API is worth doing when the content model is expected to change, when consumers should not see editor-only or internal fields, or when a stable public name is needed for something that Drupal's machine names do not express well. It is less useful for a small internal API where a coordinated release is cheap.
Treat the shaped API as a contract. Every rename or removal in JSON:API Extras is a breaking change for any client that reads the old name, so record the mapping from internal to public names in version control, test the responses with the same fixtures your front end uses, and agree a deprecation process with the consuming teams before the first release. Versioning the path prefix is one way to run two shapes side by side during a transition, but whether your chosen approach fits your hosting and caching layers, and how long you must keep old names live, are decisions to confirm with your own engineers and with the module's current documentation.
Which JSON:API Extras options fit which consumer problem
Core JSON:API derives endpoint paths from machine names, so a content type called article_landing_v2 appears in the URL exactly as it was built. JSON:API Extras lets the team set a resource path that front-end developers can read and that stays stable even if the internal bundle is later renamed. This fits projects where several front ends will be built by different teams and the URL vocabulary should match the content model's editorial language.
- Fits when: endpoint names are hard to read or leak internal naming decisions that editors never see.
- Breaks for existing consumers: any client already calling the old path receives a 404 after the rename, so the change needs a planned cutover.
- Confirm: whether the resource alias is applied to nested relationship links and to the generated entry points that clients discover first.
- Confirm: how aliases interact with the path prefix setting, since both change the public URL.
- Plan: record every alias in the consumer contract so front-end teams know which names are stable.
Before renaming anything in production, list the consumers and their hard-coded paths, then test the new names against each one in a staging environment.
Some content and fields should never leave Drupal through the API, such as internal review notes, pricing rules held for sales, or fields carrying personal data that a public consumer has no need to see. JSON:API Extras can disable whole resources and individual fields so they are absent from responses. This is a data-exposure control, and it should be designed together with the access rules that already govern entities in Drupal.
- Fits when: a field is used only by the Drupal admin screens or by a back-office process and must not reach a public front end.
- Breaks for existing consumers: any client reading the removed field will receive missing data, which can fail silently in a front end that does not check for it.
- Confirm: whether disabling a field hides it from every JSON:API response or only from collection and detail routes.
- Confirm: that disabled fields are still protected by entity and field access, because hiding a field in the API is not the same as restricting who can read it in Drupal.
- Plan: review disabled fields during each content model change, since new fields are added often and default to exposure.
Treat the list of disabled resources and fields as part of the security review, and verify the result with an unauthenticated and an authenticated request.
A path prefix places the JSON:API under a distinct base path, which is a practical way to separate consumers or to run a second shape of the API beside the first. For long-lived clients, the prefix is the most visible versioning tool available in this module, but it does not version the data model on its own. Teams should decide whether they need a true version contract or simply a boundary between audiences.
- Fits when: a new front end needs a different response shape while an older one must keep working during a transition.
- Breaks for existing consumers: changing the prefix moves every endpoint, so existing clients break unless the old prefix remains available.
- Confirm: whether the module can serve the old and new prefixes at the same time, and for how long that setup is supported.
- Confirm: how the prefix affects caching rules, reverse proxy routes and any API gateway in front of Drupal.
- Plan: document a deprecation window and the date each old prefix will stop responding, agreed with consumer owners in writing.
Before relying on prefixes for versioning, ask the team that owns each consumer how it will migrate, because a prefix alone does not tell a client which fields changed.
Field aliasing exposes a Drupal field under a different name in the API, which decouples the public property name from the internal machine name. This is useful when the content model was built by one team and consumed by others who expect different vocabulary, or when an internal field name would confuse a developer reading responses. The alias changes only what the consumer sees, so the Drupal data and its storage stay unchanged.
- Fits when: an internal machine name is unclear to consumers or when a field is renamed for clarity without a database change.
- Breaks for existing consumers: clients reading the original property name stop receiving that key, so the change behaves like a rename for them.
- Confirm: whether the alias applies to filters, sorts and sparse fieldsets, since consumers often use those parameters with the original name.
- Confirm: whether the alias is included in the schema or documentation that front-end teams generate from the API.
- Plan: keep a mapping table of internal names to public names, and version it with the rest of the consumer contract.
Run the same front-end query suite against the aliased fields before release, because filter and sort parameters are the most common place where an alias breaks an existing consumer.
JSON:API Extras configuration options compared
This table compares the main JSON:API Extras options (resource and field renaming, disabling, field overrides and path prefixes) by purpose, consumer impact, reversibility and pre-release testing. Read each row as a change you would ship to a client that already depends on the current response shape, and treat the reversibility column as the cost of getting it wrong.
| Option | Purpose | Consumer impact | Reversibility | What to test before release |
|---|---|---|---|---|
| Resource renaming | Gives an entity type or bundle a shorter or clearer public name in the API | Every client that calls the old resource path or type name must change its requests | Reversible in configuration, but clients built on the new name break if you revert | Old and new paths during the transition, and every consumer's fetch calls |
| Resource disabling | Removes an entity type or bundle from the public API | Clients receive errors for the removed resource, so this is the most disruptive change | Reversible in configuration, but data pulled during the outage window is not recovered | Each front end's build and preview routes, plus cached responses in any CDN |
| Field renaming | Changes the public key of a field in the JSON:API response | Front ends that read the old key render empty values without raising an error | Reversible, but clients using the new key break on revert | Component rendering with real content, including fields that are empty or multi-valued |
| Field disabling | Hides a field from API responses and filters | Clients that read or filter on the field lose data or get unexpected results | Reversible, and existing content keeps its values | Any filter, sort and include parameters that reference the hidden field |
| Field overrides | Adjusts how a field is exposed, such as its name or how it is treated, for a specific consumer need | Behavior varies by option, so check each override against the consumer's expected payload | Reversible per field, confirm the exact override names on the JSON:API Extras project page | Payload diff against a stored sample response for each consumer |
| Path prefix | Adds a fixed segment to all JSON:API routes, for example to separate API versions or environments | Every consumer URL changes, which affects routing, CORS rules and cache keys | Reversible, but all clients must switch paths together | Reverse proxy rules, CORS configuration and CDN cache rules for the new prefix |
| Versioning approach | Keeps two shapes live at once, typically by pairing a prefix with a separate configuration | Long-lived clients keep the old shape while new clients adopt the new one | Easiest to exit when you can retire the old prefix on a planned date | Contract tests against both shapes and a sunset plan agreed with each client owner |
| Configuration export | Stores the API shape in version-controlled configuration so changes are reviewed and deployed | No direct consumer impact, but makes unreviewed changes visible | Fully reversible through version control | Config import on a staging copy matches the production API output |
How to set up JSON:API Extras on a Drupal site
This sequence moves JSON:API Extras from an inventory of existing consumers to a tested, exported configuration that changes resource names, paths and field exposure without breaking the clients that depend on them. Each step ends with a check you can record, so the change can be reviewed before it reaches production.
Inventory consumers and current endpoints
Before changing anything, list every client that calls the Drupal JSON:API: front ends, mobile apps, integrations, scheduled jobs and partner systems. For each one, record the endpoints it calls, the fields it reads, the query parameters it sends and the owner who can approve a change. Export the current endpoint list from a staging copy of the site, using the JSON:API entry point, so the baseline is a file rather than memory. Done means you have a signed-off consumer register and a saved baseline list of paths and fields that the rest of the sequence compares against.
Decide the target naming and prefix scheme
Agree in writing how resources, fields and paths will look after the change. Decide whether a path prefix applies to the whole API, which entity types are renamed, which fields are hidden or disabled, and how long the old names will keep working during the transition. Record the decision with the consumer owners, because every rename becomes a breaking change for any client that still uses the old name. Done means a mapping table exists with one row per resource or field, showing its current name and its target name or its disabled status.
Install and enable the module in a non-production environment
Add JSON:API Extras to a development or staging copy of the site with Composer, enable it, and confirm that the site still builds and the default JSON:API routes respond as they did before. Keep the change in a branch of your configuration and avoid making overrides in the production database. Check that the baseline endpoint list from the first step still matches, since enabling the module alone should not change any path. Done means the site runs with the module enabled and the endpoint list is identical to the baseline.
Apply overrides in configuration
Make the planned changes in the staging site: set the path prefix if one is chosen, rename resources and fields, and disable those that consumers should no longer see. Apply each change through the module's configuration screens or configuration files so it can be exported. Keep the changes small enough that each one can be tested on its own. Done means the mapping table has been implemented and every override is visible in the site's configuration, not only in the running database.
Export configuration and review the diff
Export the site configuration, then review the resulting files in version control. Check that only the intended JSON:API Extras settings changed, that no unrelated settings or content references were added, and that the change is reproducible on a fresh copy of the site. Ask a second reviewer to read the diff against the mapping table. Done means the review is recorded and the configuration can be imported into another environment without manual edits.
Compare endpoint lists against the baseline
Fetch the endpoint list from the configured site and compare it with the baseline saved in the first step. Every entry should be either unchanged, renamed to the target in the mapping table, or removed as planned. Look for surprises such as entities that appeared unexpectedly or fields that remain exposed after being marked as disabled. Done means the comparison produces a short list of differences, each traced to a row in the mapping table.
Confirm disabled fields are absent from responses
Request sample resources through the new paths and check the JSON bodies. Disabled fields should not appear in collection or single-resource responses, and renamed fields should appear only under their new names. Include related resources and included relationships, since a field can still leak through an include parameter. Done means a dated record shows, for each disabled field, a response in which it is absent.
Run consumer contract tests against the new paths
Ask each consumer owner, or the team that maintains the client, to run its own tests against the staging site. Each test should call the new paths, read the fields it depends on and confirm the expected response shape, status codes and pagination behavior. Where the old and new names must coexist during a transition, test both. Record which consumers passed, which needed changes, and the date each change was accepted. Done means every consumer on the register has a recorded pass before the configuration is promoted to production.
Planning versioning for long-lived API clients
Renaming a resource type, changing a path prefix or disabling a field is a breaking change for every client that hard-codes the old path, and JSON:API Extras makes that change in one configuration screen or one export. The Extras settings for resource and field names, path prefixes and disabled fields apply to the whole API at once, so a change that looks cosmetic in Drupal can break a Next.js build, a mobile app release that is already in users' hands, or an integration nobody on the Drupal team knows about. Before any rename ships, list every consumer, record which paths and fields each one reads, and confirm with the front-end and mobile teams how long they need the old names to keep working.
There are three practical patterns, and they can be combined. A versioned prefix, such as a /v2 segment set through the path prefix setting, gives new consumers a clean contract while old clients keep the original paths for a deprecation window. Running both old and new paths in parallel means keeping two sets of resource and field names active, usually through a second route or a duplicated configuration, which doubles what must be tested and documented. Freezing the contract with consumer-driven tests means each client publishes the fields it depends on, and the Drupal build fails when a change would remove one of them. Consumer-driven tests need a maintained list of consumers and an owner for it, so they are only as good as that list.
The team that runs Drupal owns the decision of how long old paths live, and that decision has a cost. Each extra month of parallel paths adds configuration to maintain, more tests to run on every release and more places where editors and developers can confuse the two names. Ask the client to write down the window for each consumer, the owner who signs off removal and the evidence that a path is no longer called, such as access logs for the old prefix. Agree this in writing before the first rename, because a window negotiated after a change has shipped usually starts too late for the clients that need it most.
Security and operational risks of exposing a shaped API
Renaming, hiding and disabling resources changes what consumers see, but it does not replace the controls that protect the data behind the API. The cards below cover the risks that tend to appear after a shaped JSON:API goes live, and the checks that keep the configuration, caches and access rules aligned over the life of the site.
Hidden fields are not access control
Removing a field from the JSON:API configuration only changes what the endpoint publishes. Entity and field access still decide what each role can read, so a user with the right permissions can still reach data through other routes such as filters, related resources or sibling endpoints. Test each consumer role against the live endpoints, and confirm that permissions on the underlying entities and fields, not the API shape, define what may be read. Our engineers can help map these rules before launch.
Disabled resources in every environment
A resource disabled in development can reappear in staging or production if its configuration was never exported, or if an older export is imported over newer settings. Confirm that each environment exposes the same resource list, and check the endpoints directly after every deployment rather than trusting the admin screen. Keep a short checklist of disabled resources in the release notes so reviewers can verify them quickly.
Configuration drift between environments
Shaping decisions live in exported configuration, and manual edits on one server quietly diverge from the repository. Over months, field names, path prefixes and resource lists can differ between the copy consumers test against and the copy they use in production. Require all JSON:API changes to pass through version-controlled configuration, and compare exports between environments as part of each release.
Caches and CDN keys after path changes
A change to a path prefix or a renamed resource produces new URLs, while reverse proxies, CDNs and client caches may still hold responses under the old ones. Consumers can then receive stale data or errors that look like outages. Before changing a path, decide how old URLs will be served during a transition period, confirm that cache tags or purge rules cover the new paths, and test a purge in staging.
Logging of API traffic
Shaped endpoints are easy to call from many clients, so unusual request patterns and failed authorization attempts need to be visible. Decide which request details to log, such as method, path, status code and client identifier, and which to exclude, such as tokens and personal data in query strings. Confirm retention periods with your security and privacy teams before enabling logs in production.
New fields after content model changes
When editors or developers add a field to a content type, the JSON:API may expose it immediately, even if no consumer was meant to see it. Sensitive values such as internal notes, unpublished review data or staff-only references can reach public clients this way. Add a review step to every content model change that asks whether the new field should appear in each endpoint, and record the decision in the configuration.
Questions teams ask before customizing the Drupal JSON:API
What drives the cost of JSON:API Extras work?
The cost follows the number of resources, fields and consumers the change touches, plus how much of the existing API your clients already depend on. Renaming a single field on an internal consumer is small work. Reshaping resource names, disabling fields across many content types and aligning the output with several front ends takes more analysis, configuration review and regression testing. Ask any partner for a fixed-scope quote that lists each content type and endpoint in scope, the consumers that must be retested, the environments used for verification, and whether custom code is needed beyond configuration. The quote should separate one-time configuration work from any recurring support or upgrade retainer.
How long does a typical scoped JSON:API Extras change take?
Duration depends on how many resources are affected, how many consumers must be verified, and how mature the content model is. A change limited to a few resource renames or field exclusions on one site can be planned and tested quickly. Changes that cover many bundles, multiple front ends or a published API contract take longer because each consumer needs a test pass and rollout must be sequenced. Ask for a written timeline that lists the discovery step, the change list, the test environment work, the consumer sign-off points and the release window. Do not accept an estimate that does not name these steps.
What does the work need from our team?
Three groups of people are needed. Content model owners confirm which content types, fields and labels are public and which are internal. Consumer developers identify every app, front end or integration that reads the API and provide test cases or sample requests. Platform or operations staff provide a non-production Drupal environment that matches production configuration, along with access to deploy configuration and clear the caches. Without these inputs, the work tends to stall at discovery. Confirm the availability of each group before the project starts and agree who signs off on the final endpoint list.
Can an internal team customize JSON:API Extras without a partner?
Yes, a team with Drupal configuration experience can often make small changes using the module's configuration screens and exported configuration. The risk rises when the change affects a public contract, when several consumers depend on existing names, or when the team has not run an API regression check before. Internal teams should confirm they can track configuration in version control, test changes against each consumer, and document the resulting endpoints. A partner is most useful for the discovery and verification work, or for a one-time reshape before the team takes over maintenance.
How should we handle an API change that breaks an existing app?
Treat the change as a versioned contract change, not a silent edit. Before release, list every consumer that reads the affected resource or field and confirm each one against a staging copy. Where a rename cannot wait, keep the old path or field available for a defined period while consumers migrate, and document the removal date. Roll changes out with a rollback plan that covers the exported configuration and the cache state. Ask any partner to show how their quote handles regression testing, consumer communication and the decommissioning of old names.
Does JSON:API Extras change how access control works?
No. The module shapes what the JSON:API exposes, such as resource names, path prefixes and field visibility, but permissions still come from Drupal's roles and entity access rules. Hiding a field in the API is not the same as protecting it, so sensitive data must also be restricted by role and access settings. Ask the implementer to show which roles can read each exposed resource and to confirm that unpublished or internal content is excluded from every consumer-facing endpoint.
Which parts should we confirm with the module maintainers or our own environment?
Confirm the exact behavior of the module version you plan to use on your Drupal release, including how it handles path prefixes, disabled fields and any compatibility with your JSON:API and consumer libraries. Check the module's project page on Drupal.org and test each setting in a staging environment rather than relying on documentation alone. Record the module version and configuration export so that future upgrades can be compared against a known baseline.
How DeployOpen scopes and delivers JSON:API customization
DeployOpen scopes JSON:API Extras work in writing before any configuration changes, because the costly decisions are about consumers, not settings. The first step is a consumer inventory: every front end, mobile app, integration and script that reads the API, the resources and fields each one uses, and who owns each client. The second step is a naming and versioning decision for each resource that will be renamed, disabled or moved under a path prefix. Those names become part of the contract, so the written scope records which client changes are needed and which are deliberately deferred. Most engagements are fixed-scope, so the inventory, decisions and deliverables are agreed on paper before the work starts, and any change to scope is recorded the same way.
Delivery covers the configuration itself, the tests that prove it and the documentation that outlives the project. Configuration changes are made in the Drupal site's exported configuration so they can be reviewed and deployed like code, with resource and field overrides, path prefixes and disabled entries kept under version control. Consumer contract testing checks each documented request and response shape against the live API before release and again after every Drupal core or contributed module update, which is where unplanned renames usually surface. Handover includes a resource map for each consumer, the naming rules the team agreed to, and a record of what was disabled and why. Ongoing support is available as a retainer for teams that want the contract tests run after each update or want changes reviewed before they reach production. Confirm with DeployOpen during scoping which of these items are included in the fixed scope and which would be quoted separately.

