A headless Drupal site can have a beautifully optimized backend and still feel sluggish — if the JSON:API response for a single page is 200KB of fields nobody asked for, the frontend is stuck waiting on bytes it will never render. This lesson is about trimming exactly what goes over the wire to your React, Vue, or Next.js frontend, without touching a single line of frontend code.
What you'll learn in this lesson
- How to request only the fields a page actually needs with JSON:API's
fieldsparameter - How to avoid the "N+1 request" trap using
includeinstead of separate follow-up calls - How pagination keeps large collections from becoming one giant response
- Why response compression is a one-line win most sites forget to enable
Limiting fields with the fields parameter
By default, JSON:API returns every field on an entity — including ones your frontend never renders. The fields query parameter narrows that down explicitly:
/jsonapi/node/article?fields[node--article]=title,body,field_tags
The bracket syntax fields[TYPE] targets one resource type at a time — request a related type's fields the same way (e.g. fields[taxonomy_term--tags]=name) if you're also including it. Leave this off entirely during early development if you like, but treat it as mandatory before shipping: on a content type with 20+ fields, this alone can cut response size by more than half.
Avoiding the N+1 problem with include
A classic headless mistake: fetch a list of articles, then loop over them on the frontend making a separate request per article to get its author. That's N+1 requests for N articles — exactly the kind of request-count explosion this whole topic is about avoiding.
/jsonapi/node/article?include=uid,field_tags&fields[node--article]=title,uid,field_tags
One request, with the author and tags embedded directly in the response's included array. Combine include with fields on the included types too, or you've just traded "many requests" for "one enormous one."
Paginating large collections
Fetching every node of a type in one response doesn't scale past a few dozen items. JSON:API's page[limit] and page[offset] parameters cap how much comes back per request:
/jsonapi/node/article?page[limit]=20&page[offset]=0
The response's links object includes a ready-made next URL, so your frontend doesn't need to compute offsets by hand — just follow the link JSON:API already gives you.
Content-Encoding: gzip is actually present in your API responses — it's usually a one-line web server config change, and typically shrinks JSON payloads by 70-80% on top of everything else in this lesson.Quick check: your frontend needs a list of articles with each author's name shown inline. Which is the better request — fetching articles, then a separate request per author, or one request using
include=uid? (If you said the singleincluderequest, you've got it — that's exactly the N+1 problem this lesson exists to prevent, and it only gets worse as your article list grows.)
Key takeaways
- Use
fields[type]=...to request only the fields your frontend actually renders — the single highest-impact change for large content types. - Use
includeto embed related entities in one response instead of making a follow-up request per item — avoids the N+1 request pattern. page[limit]/page[offset]keep large collections from arriving as one oversized response, and JSON:API's ownlinks.nexthands you the next page URL for free.- Confirm gzip/brotli compression is actually enabled at the web server level — it's the easiest win in this whole lesson and easy to overlook.
Coming up next
Trimming what goes into a response is one lever. The next lesson covers the other one: making sure a response that hasn't changed doesn't need to be rebuilt at all, using cache tags on your API endpoints.