Why can a deprecated field be missing from a GraphQL explorer's docs pane entirely?
answer
- Two very different causes look identical here
- The field list is itself a field with an argument
- Its default answer is the narrow one
- isDeprecated and deprecationReason ride along
- includeDeprecated defaults to false
basics
~20 sIntrospection hides deprecated entries by default: the field and enum-value lists on a type take an includeDeprecated argument that defaults to false. An explorer whose introspection request omits it never receives the field, so the pane cannot show it.
solid answer
~40 sIn the introspection type system, a type's field list and enum-value list are themselves fields that take arguments: `fields(includeDeprecated: Boolean = false)` and `enumValues(includeDeprecated: Boolean = false)`. Ask without that argument and deprecated entries are simply absent from the response. An explorer renders only what it received, so a deprecated field vanishes from the docs pane and from completion — it looks exactly like a field that was deleted. Explorers that do pass `includeDeprecated: true` typically show the entry struck through and surface its `deprecationReason` next to it, which is precisely why the reason string should name the replacement and a timeline rather than say "deprecated". None of this affects execution: `@deprecated` is documentation, not enforcement, and a document selecting a deprecated field runs exactly as it always did.
code
graphql · 6 linestype Release {
id: ID!
title: String!
artistName: String @deprecated(reason: "Use Release.primaryArtist.name; removed after 2026-04-30.")
primaryArtist: Artist!
}go deeper
Recall that deprecation is a schema-level marker with a reason string and that it does not change how a field behaves. Read the reason when an explorer shows one; it names what to use instead.
Explain the mechanism: introspection's field and enum-value lists take includeDeprecated, defaulting to false, so a naive introspection request receives a silently filtered list. Be able to distinguish a deprecated field from a deleted one.
Treat the explorer's pane as evidence about one reply rather than about the schema. Insist that every deprecation reason names its replacement and a removal date, since that string is the only guidance most consumers will ever see.
Own deprecation as a lifecycle, not a label: what a reason must contain, how long a window runs, what evidence justifies removal, and who is accountable when a field carries a deprecation notice for two years and never leaves.
## What @deprecated actually is `@deprecated` is a type-system directive defined by the GraphQL specification, applied in the schema rather than in a document. Its definition carries one argument with a default: `reason: String = "No longer supported"`. In the 2021 specification edition it is valid on field definitions and enum values; later specification work extended it to arguments and input fields, with the sensible restriction that a required argument cannot be deprecated — a client has no way to stop sending it. The crucial property is that it has **no execution behaviour whatsoever**. A document that selects a deprecated field is valid, executes, and returns the same data it returned before the directive was added. Deprecation is a message to human readers and to tools; it changes nothing about the response. Removing the field later is what breaks clients, and the deprecation window exists to give them time before that happens. ## How deprecation reaches the explorer Introspection models it in three places. On a field, `isDeprecated: Boolean!` and `deprecationReason: String` say whether it is deprecated and why. On the type, the lists that contain those fields take a filter argument: ```graphql __Type { fields(includeDeprecated: Boolean = false): [__Field!] enumValues(includeDeprecated: Boolean = false): [__EnumValue!] } ``` The default is `false`. That is the whole mechanism behind the disappearing field. An introspection request that writes `fields { name type { name } }` — the obvious thing to write — receives the type's **non-deprecated** fields only. Nothing signals that anything was filtered out; the list is simply shorter. The explorer, which renders exactly what it received, shows a docs pane in which the field does not exist and a completion list that does not offer it. So the same visual symptom has two very different causes, and telling them apart is the useful skill: - The field was **removed** from the schema. Selecting it now produces an error. - The field is **deprecated and filtered out** of the introspection response. Selecting it still works perfectly. The cheap way to distinguish them is to run the field. If it returns data, it is deprecated, not gone. The thorough way is to issue an introspection request with `includeDeprecated: true` and look for the entry with its `deprecationReason` attached. ## What a good explorer does with it An explorer that passes `includeDeprecated: true` has more to work with, and by convention — none of this is specified — it renders the entry struck through, sorts it below the live fields, shows the reason inline in the docs pane, and marks a document that selects it with a warning rather than an error, since the document is valid. Some also refuse to offer it in completion while still documenting it, on the reasoning that new code should never reach for it while existing code still needs to be readable. This is why the reason string carries real weight. It is the one piece of prose that reaches a developer at the exact moment they are looking at the field they need to stop using. Consider a music catalogue graph in which `Release.artistName` is being retired in favour of a relationship: ```graphql type Release { id: ID! title: String! artistName: String @deprecated(reason: "Use Release.primaryArtist.name; removed after 2026-04-30.") primaryArtist: Artist! } ``` The reason names the replacement by its exact path and states when the field goes away. A reason of `"deprecated"` or `"old"` — or the default `"No longer supported"`, left in place by omitting the argument — tells the reader nothing they had not already worked out from the strikethrough, and it costs a conversation with the owning team. ## The interview point underneath The question looks like trivia about one argument name, and at one level it is. What it is actually testing is whether a candidate believes the explorer's field list is the schema. It is not: it is a rendering of one introspection response, and that response was shaped by the arguments the explorer chose to send. A candidate who reasons "the pane doesn't show it, so it doesn't exist" will also mis-diagnose an empty pane against an endpoint that does not answer introspection, and will trust the completion list over the deployed schema. The pane is evidence about a reply, not about reality.
- Does selecting a deprecated field in a document cause a validation failure or an execution error?Neither. `@deprecated` has no execution behaviour: the document is valid, the field resolves, and the response is unchanged. It is a signal to readers and tools only. Tooling may surface a warning, and a schema linter may fail a build on it, but that is a policy a team chose — not something the specification does. The breaking moment comes later, when the field is actually removed.
- A field you know exists is absent from the explorer's docs pane. How do you tell deprecation from deletion in ten seconds?Run it. Write a document that selects the field and execute it: if data comes back, the field is present and merely filtered out of the introspection response as deprecated; if you get an error saying the field is not defined on the type, it is genuinely gone. For the reason string, re-run introspection on that type with `includeDeprecated: true` and read `deprecationReason`.
- What makes a deprecation reason useful rather than decorative?It names the replacement by its exact schema coordinate and states when the field disappears — "Use Release.primaryArtist.name; removed after 2026-04-30". That string is read at the precise moment someone is deciding what to write instead, often inside an explorer with no other context available. A bare "deprecated", or the default "No longer supported" left in place, forces a conversation with the owning team for information that fits in one line.
Asking a type for its fields is like asking a catalogue for its titles: unless you say "including the ones we've stopped stocking", you get the current list and no hint that it was filtered.
saying these in an interview costs you the question
- Thinks a deprecated field stops resolving or starts erroring
- Treats the explorer's field list as the definitive schema
- Assumes deprecation is enforced by validation
- Cannot distinguish a removed field from a filtered one
- Writes reasons like "deprecated" with no replacement named