Every HTTP request carries fixed overhead — TLS handshake, DNS lookup, connection setup — before a single byte of your actual data arrives. A frontend that fires off ten small requests to render one page pays that overhead ten times over. Batching is simply combining what would be several requests into one, and JSON:API gives you two different tools for it depending on the shape of the problem.
What you'll learn in this lesson
- How
includebatches related-entity fetching into a single request - How to fetch multiple, unrelated resource collections in parallel instead of sequentially
- When a custom REST or GraphQL resource is actually the better fit than stacking JSON:API tricks
Batching related entities with include
You met this briefly in the response-size lesson — it's worth revisiting here specifically as a batching technique. Instead of fetching an article, then separately fetching its author, then separately fetching its tags:
/jsonapi/node/article?include=uid,field_tags
One request returns the article plus the author and tags embedded in the response's included array. This is the right tool whenever the "batch" is really just "one entity and the things it references."
Fetching unrelated collections in parallel
Not every batching problem is about related entities. Sometimes your homepage genuinely needs three unrelated things — the latest articles, the site's promoted events, and the current user's profile. JSON:API has no built-in "multi-resource" endpoint for this, so the right move on the frontend is firing these as concurrent requests rather than sequential ones:
const [articles, events, profile] = await Promise.all([
fetch('/jsonapi/node/article?page[limit]=5'),
fetch('/jsonapi/node/event?filter[promoted]=1'),
fetch('/jsonapi/user/user/' + userId),
]);
This isn't reducing the request count the way include does — it's reducing the total wall-clock time, since three requests firing at once finish in roughly the time of the slowest one, not the sum of all three.
When a custom resource beats stacking JSON:API tricks
If a single page genuinely needs data shaped nothing like any one entity — a true aggregate view combining counts, unrelated entity types, and computed values — forcing that through JSON:API's include/filter vocabulary often produces a fragile, hard-to-read request URL. At that point, a purpose-built REST resource (from the REST/API Integration topic earlier in this course) or a GraphQL query designed around exactly that page's shape is usually the more maintainable answer, even though it's more code up front.
include onto one request can back you into the exact problem this lesson is trying to solve — one enormous response instead of several small wasteful ones. Batch what genuinely belongs together on one page; keep unrelated data in separate, independently-cacheable requests.Quick check: your frontend needs an article and its comments — genuinely related data for one page. Should you reach for
include, or fire two parallel requests withPromise.all? (include— comments are directly related to the article, so one request withinclude=commentsbeats two separate round trips. SavePromise.allfor genuinely unrelated data, like this lesson's articles/events/profile example.)
Key takeaways
- Use
includeto batch an entity with its directly related data into a single request. - Use
Promise.all(or your framework's equivalent) to fire genuinely unrelated requests concurrently rather than sequentially — this cuts wall-clock time, not request count. - When a page's data shape doesn't map cleanly onto any single entity, a purpose-built REST or GraphQL resource is often more maintainable than a heavily-parameterized JSON:API request.
- Don't over-batch — combining unrelated data into one giant request just recreates the oversized-response problem from earlier in this topic.
Coming up next
The final lesson in this topic — and this course — looks at GraphQL specifically: how to structure queries so you get precisely the data you asked for, no more and no less, which is GraphQL's whole reason for existing in a headless stack.