@defer and @stream
The book page shows the title and price instantly from a fast table, but the reviews come from a slow service that takes two seconds. Normally the whole response waits for the slowest field, so the reader stares at a blank page. @defer and @stream let the server send the fast part now and the slow part when it is ready, all in one request.
The rule
@defersends a fragment later;@streamsends a list a few items at a time.
This is called incremental delivery. It is still being added to the GraphQL specification, and some servers and clients already support it, so check yours before relying on it.
@defer goes on a fragment spread or an inline fragment, never on a plain field:
query BookPage($id: ID!) {
book(id: $id) {
title
price
... @defer(label: "reviews") {
reviews(first: 5) { rating text }
}
}
}The first part of the response holds title and price. A later part adds reviews once they are ready.
@stream goes on a field that returns a list:
query BrowsePage {
books(first: 50) @stream(initialCount: 10) {
title
price
}
}The first part holds the first 10 books; the rest arrive in later parts as the server produces them.
Both directives take an optional if: (so a variable can turn them off) and a label to help the client tell parts apart. Over HTTP, the parts travel in one response that stays open until the last part is sent. This is not a subscription: when everything has arrived, the request is over. Put the parts together and you get exactly the data the same query would return without the directives.
The shortcut
Look at the page and ask "what can the reader use first?" Fast, essential fields go in the initial part. A slow object-shaped section → wrap it in ... @defer. A long list → @stream with a small initialCount.
Find the slow part
titleandpriceare fast;reviewswait on a slow service.
The trap is putting @defer straight on a field, as in reviews @defer. It belongs on a fragment; @stream is the one that goes on a (list) field.
Drills
Answer fast — trust the rule.
Where can @defer be placed?
What does the first part of books(first: 50) @stream(initialCount: 10) { title } contain?
How do @defer and @stream differ from a subscription?
Why is book(id: "b1") { title @stream } wrong?
When all the parts of a deferred response are merged, what do you get?
Remember
@defersends a fragment later;@streamsends a list a few items at a time.- Fast fields first; slow sections →
... @defer; long lists →@stream(initialCount: n). - Trap:
@deferbelongs on fragments, and support depends on your server.
