In a GraphQL response, how does a fragment spread's position affect key order?
answer
- Order comes from the document, not the schema
- Where the definition sits is irrelevant
- Expanded in place, at the spread
- A duplicate key keeps its first position
- Never read a response object positionally
basics
~20 sResponse keys follow the order the document requests them, with each fragment expanded in place at its spread. A response key that appears twice keeps its first position, so a later duplicate never moves it to the end.
solid answer
~50 sThe executor collects fields by walking a selection set in document order, keying each one by its response key, and it recurses into a fragment's selection set at the point of the **spread** - not at the point of the definition. So moving a fragment definition around the document changes nothing, while moving a spread reorders the response. When two selections share a response key they merge into a single entry, and that entry stays where the key first appeared, which is why selecting a field inline and again inside a fragment yields one key at the earlier position rather than a duplicate at the end. The ordering itself is specified, but it is a property of the document rather than of the schema, so any consumer that reads a response object positionally is coupled to how somebody happened to arrange the spreads.
code
graphql · 13 linesquery ClaimExport($id: ID!) {
claim(id: $id) {
claimNumber
status
...ClaimFinancials
}
}
fragment ClaimFinancials on Claim {
reserveCents
paidToDateCents
claimNumber
}go deeper
It is enough to know that a spread's fields appear where the spread is written, not appended at the end, and that asking for the same field twice does not produce the same key twice.
Be able to explain field collection in your own words: selections walked in document order, keyed by response key, fragments recursed into at the spread, a repeated key merging into the entry that already exists.
Show the production judgement: the ordering is specified but is a property of the document, so a positional consumer breaks on a harmless-looking refactor. Name the safe contrast - list element order is real data and may be relied on.
Own the contract question: decide what your organisation promises consumers about response shape, keep positional coupling out of exports and integrations, and make sure document refactors are not treated as invisible when downstream systems read shape rather than fields.
## What the specification actually says about order A GraphQL response is defined as a **map**, and the specification requires that map to be *ordered*: entries appear in the order the corresponding fields were requested, with fragments expanded in place. It is one of the few places where GraphQL commits to something a JSON object normally leaves open. The specification also concedes that a serialization format with no ordered-map concept may lose the ordering, and that this is not a violation - which is the first hint that consuming order is fragile even though it is specified. The mechanism is field collection. The executor walks the selections of a selection set in document order and builds a map keyed by **response key** - the alias if a selection has one, otherwise the field name. When it meets a field whose response key is already present, it appends that selection to the existing group and the group does not move. When it meets a fragment spread, it recurses into that fragment's selection set at that point and carries on collecting. Two consequences fall straight out of that: * **A spread's fields appear where the spread is**, not at the end, and not where the fragment happens to be defined. * **A repeated response key keeps the position of its first occurrence.** The later selection merges into the earlier entry instead of appending a second one. ## The document ```graphql query ClaimExport($id: ID!) { claim(id: $id) { claimNumber status ...ClaimFinancials } } fragment ClaimFinancials on Claim { reserveCents paidToDateCents claimNumber } ``` `claimNumber` is selected twice - once inline, once inside the fragment. The response has four keys, in this order: ```json {"data":{"claim":{"claimNumber":"CLM-88214","status":"OPEN","reserveCents":412500,"paidToDateCents":186000}}} ``` `claimNumber` is first because that is where it first appeared; the fragment's copy merged into that entry and contributed no second key. The two financial fields sit exactly where the spread sits. ## The ordering assumption that broke A nightly claims export serialized this response and wrote a CSV positionally - first key to the first column, second key to the second, and so on. A refactor then moved the spread to the top of the selection set so the financial block would read first: ```graphql ...ClaimFinancials claimNumber status ``` Nothing else changed: no schema edit, no change to the fragment, no validation error, no failed request. But the key order became `reserveCents`, `paidToDateCents`, `claimNumber`, `status`, and the export wrote claim numbers into the reserve column for a full night before anyone noticed. The lesson is not that the ordering rule is wrong - the executor did precisely what the specification says. It is that the order is a property of the *document*, and the document is the artefact people refactor most freely. ## Definition position is irrelevant Moving the fragment definition above the operation, or to the end of the file, changes nothing whatsoever. Fragment definitions are top-level and unordered; only the position of the spread takes part in collection. This is a common muddle - people assume a fragment "runs" where it is written, and then reason about response order from the layout of the file rather than from the selection sets. ## Merging, briefly Two selections sharing a response key collapse into a single entry, and for composite fields their sub-selections are collected together in the same first-occurrence way, so ordering inside a merged object follows the same rule one level down. Whether such a merge is *allowed* at all - it requires the same field with the same arguments - is a separate matter; the point here is only that a legal duplicate yields one key, at the earlier position, resolved once. ## What to rely on Rely on the **set** of keys and on their values. Do not consume a response object positionally. Even with the ordering requirement in force, several things sit between the executor and the calling code: a normalized cache reassembling objects from its own store, generated result types with their own declaration order, an intermediary that re-serializes the body, or a host language whose map type is unordered. And the ordering you would be leaning on changes the moment anybody moves a spread. The contrast worth naming in an interview is **list order**, which is a completely different thing: the elements of a list field come back in the order the resolver produced them, that order is meaningful data, and callers should absolutely depend on it. Object key order is an artefact of how the document was written; list element order is a value the server chose. ## Saying it in an interview Give the rule in one sentence - collected in document order, fragments expanded in place, duplicates merging at the first occurrence - then the failure it enables, then the distinction between key order, which you should not depend on, and list order, which you should. That progression shows you know the specified behaviour and also why knowing it is not permission to use it.
- If a field is selected inline and again inside a spread fragment, do you get two response keys?No, one. The two selections share a response key, so they merge into a single entry that stays at the position of the first occurrence, and the field is resolved once for that set of arguments. For a composite field the sub-selections merge too, and the sub-keys are ordered by first occurrence in the same way. Whether the merge is permitted at all depends on the two selections naming the same field with the same arguments.
- Is the order of elements in a list field decided the same way?No, and the contrast matters. Object key order is an artefact of the document, decided by where fields and spreads were written. List element order is data: the elements come back in the order the resolver produced them, positions are preserved through execution, and callers are entitled to depend on it. Confusing the two leads people either to distrust list order or to trust key order.
- The ordering is specified, so why is depending on it still a bad idea in a real client?Because almost nothing downstream promises to carry it. The specification itself allows a serialization format with no ordered-map concept to lose the ordering, and in practice a normalized cache, generated result types, a re-serializing intermediary or an unordered map type in the host language can each reorder the object. On top of that, the order changes whenever anyone moves a spread, which is an edit no reviewer treats as behavioural.
Think of the document as a print order rather than a filing cabinet: the page order follows where you inserted each block, and asking twice for the same block does not print it twice, it just keeps the slot where you first asked.
saying these in an interview costs you the question
- Thinks fragment fields always land after inline fields
- Believes definition order controls response order
- Expects a duplicated field to appear twice
- Says response key order is unspecified and arbitrary
- Reads response objects positionally in a consumer
- Confuses object key order with list element order