In fragment colocation, what does a fragment's type condition bind a view to?
answer
- Look at what follows `on`
- A schema type, not a file
- Views move; the contract does not
- Fields are pinned, values are not
- Read only what you selected
basics
~20 sTo a schema type, never to the view. A fragment written on Order says only give me an Order, so any parent selecting a field of that type can spread it, and renaming the view changes nothing.
solid answer
~50 sThe part after `on` is a **schema type**, and that type - not the file, not the view's name - is the contract. A view whose fragment reads `on Courier` can be dropped anywhere a parent selects a field of type `Courier`, and can be renamed, moved or reused without touching the document. The corollary is that reuse across *different* types does not come free: a view asked to render both an `Order` and a `PickupTicket` needs a fragment per type, or one fragment on an interface both implement, which is a schema-design decision rather than a client one. The binding is also only over **fields**, not values: a colocated fragment fixes which fields arrive, and says nothing about which values those fields may hold, which is why a new enum member can break a view whose document never changed.
code
graphql · 15 linesfragment CourierCard_courier on Courier {
displayName
etaMinutes
vehicle
}
query OrderTracking($orderId: ID!) {
order(id: $orderId) {
courier { ...CourierCard_courier }
}
}
query DispatchBoard {
onShiftCouriers { ...CourierCard_courier }
}go deeper
Know that the name after on is a type from the schema, and that it is what decides where the fragment can be spread - the view's own name plays no part in the request.
Be able to work the consequences both ways: a view is portable to any parent field of that type, and a view reused across two different types needs two fragments or a shared interface.
Demonstrate the discipline and its limit - masking so a view reads only its own fields, and knowing that pinning fields never pins the value space, which is how an unhandled enum member reaches production silently.
Own when the schema should grow an interface to serve genuine cross-type reuse versus when that abstraction only models the UI, and set the house rule on enum growth that client views can survive.
## `on` names a type in the schema A fragment definition carries a type condition - `fragment CourierCard_courier on Courier` - and that name must resolve to a composite output type in the schema. It is the only binding a fragment has. The fragment's *name* is a label unique within the document; the file it sits in, the view it was written for and the screen that spreads it are all invisible to the server. Everything colocation gets right, and everything it does not protect you from, follows from that one fact. ## The view is portable because the contract is a type Because the contract is `Courier`, the same colocated fragment travels to any position in any document whose parent field is a `Courier`: ```graphql fragment CourierCard_courier on Courier { displayName etaMinutes vehicle } query OrderTracking($orderId: ID!) { order(id: $orderId) { courier { ...CourierCard_courier } } } query DispatchBoard { onShiftCouriers { ...CourierCard_courier } } ``` One view, two screens, two parents, no edit. Renaming the view, moving its file, or wrapping it in another view changes none of this, because none of it was ever named in the document. This is the practical reason colocation survives refactoring where a hand-written screen query does not: the query encoded the screen's structure, the fragment encodes only a type. ## Reuse across different types is not free The flip side is exactly as sharp. A summary view asked to render an `Order` on one screen and a `PickupTicket` on another cannot spread a single fragment on `Order` in both places - the type condition would not be satisfiable where a `PickupTicket` is. The honest options are two fragments, one per type, or a fragment on an interface that both types implement. The second is a schema-design commitment: somebody must decide that `Order` and `PickupTicket` really are two kinds of one thing, name the interface, and put the shared fields on it. Reaching for the interface only because the UI happens to reuse a card is how a schema acquires abstractions that model the front end rather than the domain. Where a spread is legal at all - which type conditions may appear inside which selection sets - is a property of fragments generally rather than of colocation, and it is the reason the type condition is checked before anything executes. ## Read only what you declared The discipline that makes colocation more than a filing convention is that **a view reads only the fields its own fragment selected**, even when a sibling's fragment happened to fetch more onto the same object. Some client libraries enforce this by handing each view a masked view of the data; nothing in GraphQL does. If a status chip reads `placedAt` because the line-items fragment next door selected it, the chip breaks silently the day that other view is deleted - and the deletion looked completely safe, which is the whole point of colocation and exactly what the shortcut throws away. ## The binding is over fields, not values This is the limit worth being able to state. A colocated fragment fixes the *shape* of what arrives. It says nothing about the *domain* of the values. In one restaurant ordering graph, `OrderStatus` had five members and a status chip whose fragment selected `status` mapped each to a label and colour. A courier-assignment step shipped, and the enum gained `AWAITING_COURIER`. Nothing in the client changed: the fragment still selected `status`, the document still validated, the response still contained the field. The chip's mapping simply had no branch for the new member and fell through to an empty label - a blank chip on roughly 3.4% of live orders, unnoticed for eleven days because nothing anywhere threw. The lessons are two. First, treat every enum you select as **open**: always have a default branch, and render something honest for a value you do not recognise. Second, do not oversell colocation in an interview. It localises which fields a view depends on, and that is genuinely valuable; it cannot localise a dependency on the set of values a field may hold, on an argument's semantics, or on a nullable field starting to be null. Whether a schema may add an enum member at all, and with what notice, is a schema-evolution policy question, not something the document can express. ## Naming as a consequence The `Owner_propName` convention - `CourierCard_courier` - reads correctly once you see the type condition as the contract: the suffix names the value the view is handed, and the prefix keeps names unique in a document that may staple together fragments from a dozen files. If a view is handed two objects, it owns two fragments, one per type.
- A view must render both an `Order` and a `PickupTicket`. What are your options?Either write one colocated fragment per type and let the view accept both shapes, or have the schema expose an interface both types implement and write a single fragment on that interface. The second is cleaner to consume but is a schema commitment - the interface should exist because the domain has that abstraction, not because one card is reused.
- A sibling fragment already selects `placedAt` on the same object. May a view read it without declaring it?It will be present in the response, so it works today, and it is still a bug. The field is on the object only because another view asked for it; delete that view and this one breaks with no visible cause. Some client libraries mask data to make the mistake impossible, but nothing in GraphQL does - the discipline is yours to keep.
- Does a colocated fragment protect a view from a breaking schema change?It makes the blast radius findable, not smaller. Removing a field still breaks every view selecting it, but the type condition and the selection make the affected fragments mechanically searchable, so the change becomes a list of files rather than a hunt. It gives no protection at all against value-level changes such as a new enum member.
saying these in an interview costs you the question
- Says the fragment is scoped to the view that defines it
- Thinks renaming the view changes the document
- Reads fields a sibling fragment happened to select
- Assumes one fragment can be spread on any type
- Believes colocation guards against new enum values
- Treats the fragment name as something the server resolves