What do GraphQL's __schema and __type(name:) meta-fields return, and where may they appear?
answer
- The server describes itself in its own language
- One whole type system, one single lookup
- Roots, types and directive definitions
- Query operation root only, never at depth
- Unknown type name returns null
basics
~20 s__schema returns the whole type system: every type, the query, mutation and subscription root types, and the directive definitions. __type(name:) returns one named type, or null when the schema has none. Both are legal only at a query operation's root.
solid answer
~40 sBoth are meta-fields on the **query root type**, so a caller learns the contract by sending an ordinary document over the ordinary transport — there is no side channel. `__schema` returns a `__Schema` record: `types` (every type in the system), `queryType` (non-null), `mutationType` and `subscriptionType` (nullable, since a schema need not have them), and `directives` (the directive **definitions**, with their arguments, locations and repeatability). `__type(name: String!)` is the targeted lookup and returns a **nullable** `__Type`, so an unknown name yields `null` rather than an error. The specification restricts both to the root of a **query** operation — not a mutation root, not a subscription root, and not at depth. Like `__typename`, they are meta-fields, so they never appear in the query root type's own `fields` list.
code
graphql · 15 linesquery SchemaProbe {
__schema {
queryType { name }
mutationType { name }
subscriptionType { name }
types { name kind }
directives { name locations isRepeatable }
}
__type(name: "Artwork") {
kind
description
fields { name }
interfaces { name }
}
}go deeper
Know that a GraphQL server can describe itself, that you ask with a normal query, and that __schema gives the type list and root types while __type looks up one type by name.
Explain the __Schema record field by field, why mutationType and subscriptionType are nullable, and the rule that both meta-fields are legal only at the root of a query operation. Expect to be asked what a missing __type name returns.
Be ready to say what an introspection result faithfully preserves and what it drops — descriptions survive, comments, ordering and file layout do not — and why schema comparison must run over a canonical printed form rather than raw files.
Frame introspection as the contract-distribution mechanism for the organisation: who is entitled to read a running server's type system, whether the checked-in artefact or the live endpoint is authoritative, and what that choice costs consumers.
## The schema, asked for in the same language as the data A GraphQL server describes its own type system through two meta-fields on the **query root type**: `__schema` and `__type(name:)`. There is no side channel, no well-known path and no separate protocol — a caller sends an ordinary document over the ordinary transport and gets an ordinary response back. That single design decision is the reason the ecosystem around GraphQL exists at all: anything that can send a query can learn the whole contract. ## `__schema` `__schema` returns a single `__Schema` record whose fields are the schema itself, decomposed: * `types: [__Type!]!` — every type in the type system. * `queryType: __Type!` — the object type serving as the query root. Non-null, because a schema must have one. * `mutationType: __Type` — nullable; a schema need not support mutations. * `subscriptionType: __Type` — nullable, for the same reason. * `directives: [__Directive!]!` — the directive **definitions** the schema declares, each with its name, its arguments, the locations it may be applied at, and whether it is repeatable. Note what `types` contains. It is not only the types you wrote. A museum collection schema whose SDL file declared 49 type definitions came back with 62 entries: the 49 authored types, the five built-in scalars (`Int`, `Float`, `String`, `Boolean`, `ID`), and the eight introspection meta-types themselves — `__Schema`, `__Type`, `__Field`, `__InputValue`, `__EnumValue`, `__Directive` and the two enums `__TypeKind` and `__DirectiveLocation`. Introspection describes introspection; that is not a bug, and a consumer that renders `types` unfiltered will show the meta-types to its users. ## `__type(name:)` `__type` takes a required `name: String!` and returns a nullable `__Type`. It is the targeted probe: when you already know which type you care about, you ask for that one instead of pulling the whole type system. Because the return type is nullable, a name the schema does not define yields `null` in `data` — **not** an error, and not a fuzzy match. Code that treats a missing type as an exception will be surprised by a quiet null. ```graphql query SchemaProbe { __schema { queryType { name } types { name kind } directives { name locations isRepeatable } } __type(name: "Artwork") { kind description fields { name } interfaces { name } } } ``` ## Where they may appear The specification allows `__schema` and `__type` **only at the root of a query operation**. They are not selectable at the root of a mutation or a subscription, and they are not selectable at depth — there is no `artwork { __schema { ... } }`. This is easy to forget because `__typename`, the third meta-field, has the opposite rule: it is available almost everywhere and forbidden only at a subscription root. Like `__typename`, these two are meta-fields rather than schema fields, so they never appear in the query root type's own `fields` list. A tool that reconstructs SDL from an introspection result and then re-introspects the reconstruction gets the same answer, because nothing about them lives in the type system. ## What comes back is a record graph, not a document An introspection result is structured data: types, fields, arguments, enum values, descriptions. Descriptions survive, because a description is part of the type system — it is the block string attached to a definition. What does **not** survive is anything that is only text: `#` comments, blank lines, the order in which definitions were written, and the file boundaries the author used. An SDL printer that reads an introspection result produces a canonical rendering of the same type system, not a byte-for-byte copy of the author's file. Teams that diff schemas learn this quickly: compare the printed canonical form on both sides, never the raw files. ## What it is for, in an interview answer The honest framing is that `__schema` turns a running server into the authoritative description of its own contract. Every tool that offers field completion, every generator that produces typed client code, every checker that compares a deployed schema to the one clients were built against is ultimately a consumer of these two meta-fields. That is also why the *availability* of introspection on a public endpoint is an operational decision with consequences beyond convenience — a topic in its own right. ## Watch for * Claiming the server exposes its SDL text at some conventional URL. Nothing in the specification says so. * Selecting `__schema` inside a mutation, or at depth. * Treating an unknown `__type` name as an error rather than a null. * Confusing `__type(name:)`, a root lookup, with `__typename`, a per-value discriminator.
- What does __type return for a name the schema does not define?Null. Its return type is a nullable `__Type`, so a miss is an ordinary null in `data` — not a request error, not a field error, and certainly not a fuzzy match. Consumers that treat an absent type as an exception need to check for the null explicitly.
- Does the __schema types list contain more than the types the author wrote?Yes. It also carries the five built-in scalars and the eight introspection meta-types — `__Schema`, `__Type`, `__Field`, `__InputValue`, `__EnumValue`, `__Directive`, `__TypeKind` and `__DirectiveLocation`. A museum schema declaring 49 types reports 62 entries. Anything rendering that list to humans usually filters the double-underscore names.
- Where does an introspection result list the schema's directives, and what does each entry carry?Under `__schema { directives }`, as `__Directive` records: `name`, `description`, `args` as `__InputValue` records, `locations` from the `__DirectiveLocation` enum, and `isRepeatable`. These are the **definitions** the schema declares, which is a different thing from where those directives have been applied.
saying these in an interview costs you the question
- Claims the server serves its SDL text at a conventional URL
- Thinks __schema is a normal field you implement
- Selects __schema at depth or on a mutation root
- Says an unknown __type name raises an error
- Confuses __type(name:) with the __typename meta-field