Within one GraphQL document, what do selection sets fix about over-fetching and under-fetching, and what do they not?
answer
- Two different problems, two different residues
- The payload shrank; did the intent?
- Edges you can walk versus values you must wait for
- Response size stopped predicting cost
- A field nobody renders is still requested
basics
~20 sSelection sets fix the response shape — only selected keys come back — and nesting removes dependent round-trips. They do not stop a client selecting fields nothing renders, do not shrink backend work, and cannot remove a round-trip that waits on a returned value.
solid answer
~50 sThe genuine wins are both about the document. **Over-fetching of the response** disappears because the payload has exactly the response keys the client selected — a `Shipment` type declaring 41 fields returns the four you asked for. **Under-fetching by round-trip** disappears where the schema declares the edge: shipment → legs → terminal → carrier arrives in one request instead of a chain of dependent calls. What is *not* fixed: the client can still select fields nothing on screen renders, so over-fetching becomes an authoring discipline rather than something the protocol prevents; a narrow selection does not by itself narrow what the server reads from its backends; and where the schema has no edge — or where an argument must come from a previous response — the client still round-trips, because no field can consume another field's result inside the same document.
code
graphql · 10 linesquery TrackingWidget($id: ID!) {
shipment(id: $id) {
reference
status
currentLeg {
terminal { code }
carrier { name }
}
}
}go deeper
Know the basic claim and the mechanism behind it: the response carries only the fields the document selected, and nesting lets one request follow relationships the schema declares.
Explain both problems separately and give the mechanism for each — response keys come from the document, and a nested selection replaces a chain of dependent calls. Start noticing that the client, not the server, decides the payload.
Qualify the claim in both directions. Be ready to say that payload size is not a cost proxy, that unused selected fields are a real defect class, and that a dependency on a value from a previous response still costs a round-trip.
Own the residue as a programme: how per-field usage data is collected and acted on across client teams, how request cost is accounted for when response size no longer signals it, and where you accept a second round-trip instead of bending the schema to avoid one.
## Two claims, and the part of each that survives “GraphQL solves over-fetching and under-fetching” is the sentence every candidate has read. A senior answer separates the part that is true at the *document* level from the part that quietly moves the problem somewhere else. ### What is genuinely fixed: the response shape A fixed-response endpoint returns whatever its author decided the representation is. A selection set makes the caller decide, per request. In a freight-tracking graph, `Shipment` may declare 41 fields — customs status, declared value, hazardous-goods flags, a dozen timestamps. A tracking widget selects `reference`, `status`, `eta` and the terminal code of the current leg, and that is precisely what comes back. Nothing negotiates, nothing is stripped by a proxy: the response object's keys *are* the document's response keys. This is a real and complete fix for one specific thing — bytes on the wire that the caller never asked for — and it holds without any server-side cooperation beyond implementing the schema. ### What is genuinely fixed: dependent round-trips Under-fetching is the mirror problem: the response you got is not enough, so you call again with something from it. Nesting removes that whenever the schema declares the edge. Walking shipment → legs → terminal → carrier is one request and one latency, not four sequential ones. On a high-latency connection this is usually the larger of the two wins, and it is why the selection set is a *tree* rather than a field list. ## What is not fixed **The client can still ask for what it does not use.** Nothing in GraphQL checks that a selected field is rendered. Selections rot: a field stays in a document long after the component that displayed it was deleted, and every request keeps paying for it. One freight-tracking team measured its shipment payload down from 18.6 KB to 2.3 KB and called over-fetching solved — while the document still selected `customsStatus`, which nothing on the screen rendered. When that field began serving stale values from a lagging upstream, it degraded a screen that did not display it: the request was still asking for data nobody read. Precision became an authoring discipline, not a property of the protocol. **A narrow selection is not narrow backend work.** The response can shrink while the work behind it does not. Whether a server narrows its own reads to the selection is a server-side concern, and the honest senior statement is that payload size stops being a proxy for request cost. A 900-byte response can be the most expensive request of the day, and a 40 KB one can be free — which is why cost is measured on the document, not on the response. **Some round-trips cannot be removed.** Two limits bite. First, you can only traverse edges the schema declares; if `Carrier` exposes no path to its service bulletins, that is a second request no matter how the document is written. Second, and more fundamental: **no field can take another field's result as an argument** inside one document. If you must search by reference to learn an id, then query by that id, the dependency is on the value, not on the shape, and the selection set cannot express it. This is the ceiling on “one request per screen”, and a candidate who names it is showing they have hit it. **And one asymmetry that runs the other way.** The same nesting that removes round-trips lets one small document imply an enormous amount of work — a deep or repeated selection over a modest schema. The client-chosen document is simultaneously the fix for over-fetching and the reason an unguarded endpoint needs bounding. ## How to talk about it Name the two problems separately, because they have different fixes and different residues: * Over-fetching → fixed *for the payload*, unfixed *for the intent*. The protocol guarantees you receive only what you asked for; it guarantees nothing about whether you needed it. * Under-fetching → fixed *for schema-declared edges*, unfixed *for value dependencies*. Then say what you would do about the residue: treat unused selected fields as a real defect class and lean on per-field usage data to find them; stop reasoning about cost from response size; and accept that a screen whose data has a value dependency needs two requests, rather than contorting the schema to pretend otherwise. ## The interview signal Juniors recite the claim. Seniors qualify it in both directions — what the selection set really removed, what it merely relocated — and can point at the mechanism for each. That distinction, not the slogan, is what the question is testing.
- A team reports payloads down by 87% but backend latency unchanged. What does that tell you?That the win was on the wire, not in the work. The selection set narrowed the response keys, but whatever the server reads per field did not change with it. Payload size is not a cost proxy in GraphQL: the useful measurements are per-field resolution counts and timings, and the document's own shape, not the number of bytes returned.
- How would you find fields clients select but never use?You cannot see rendering from the server, so you approach it from both ends: per-field usage telemetry tells you what is *selected* and by which operation, and that list is then reconciled against the client code that reads each response key. Fields selected by an operation whose result is never read are the candidates. Treat them as a defect, not as harmless.
- Does a client selecting fewer fields always reduce the request's cost?No. Cost follows which fields resolve and what each one does, so dropping three cheap scalars changes almost nothing while keeping one field that fans out dominates the request. Cost has to be reasoned about on the document — which fields, at what multiplicity — rather than on how many keys came back.
Ordering a la carte stops the kitchen sending you dishes you never wanted, and lets you order the starter and main together. It does not stop you ordering food you will not eat, and it cannot let you choose the wine after tasting a dish you have not been served yet.
saying these in an interview costs you the question
- Claims a smaller payload means less server work
- Says GraphQL eliminates over-fetching entirely
- Thinks any screen can always be one request
- Cannot name a round-trip nesting will not remove
- Uses response size as a proxy for request cost
- Assumes selected always means rendered