GraphQL September 2025 spec: first major edition since October 2021
Source: GraphQL blog (Lee Byron)
The GraphQL working group shipped a named specification edition again after a long pause — the September 2025 spec replaces October 2021 as the baseline that thousands of servers, clients, and codegen tools target. It's the first edition in nearly four years, and it lands at a moment when the audience for GraphQL has changed: humans still write most of the queries, but a fast-growing share of clients are LLM agents that need predictable, machine-friendly schemas.
This is the first edition of the specification since October 2021, and it reflects years of steady, collaborative work from the GraphQL community.
The announcement frames two priorities: stability for existing platforms (large public APIs, federation deployments, codegen ecosystems) and expressiveness — especially for AI-first clients that need predictable documents, coordinates, and errors.
TL;DR
- `@oneOf` input objects — mutually exclusive arguments as a first-class schema feature.
- Schema coordinates — stable, machine- and human-readable pointers into types and fields.
- Descriptions on executable documents — operations and fragments can carry their own descriptions.
- Richer deprecation —
@deprecatedworks on more schema locations. - Full Unicode in the grammar for identifiers and string literals.
- Clearer execution semantics that make tools and AI agents more reliable.
`@oneOf` input objects
Input objects with mutually exclusive fields used to require either nullable union fakery or runtime validation in resolvers. The September 2025 edition makes the pattern a first-class schema feature:
input MediaSource @oneOf {
url: String
upload: Upload
externalId: ID
}
type Mutation {
createPost(media: MediaSource!): Post!
}Clients must supply exactly one of url, upload, or externalId. The server rejects ambiguous payloads at validation time, before the resolver runs. Three real wins:
- Forms and CLIs — a single schema cleanly encodes "either A or B".
- Codegen — generators emit discriminated unions or sum types, which TypeScript, Swift, and Kotlin clients can use without runtime checks.
- AI agents — models writing GraphQL queries can read the schema and know exactly which fields to populate, reducing the rate of malformed mutations.
The dedicated explainer post in the GraphQL blog goes deeper into the discussion and migration patterns.
Schema coordinates
A long-standing gap: how do you refer to a specific field, argument, or directive in a tool? Different libraries used different syntaxes, which made integrations fragile. The September 2025 edition standardizes schema coordinates:
- `User` — a type.
- `User.email` — a field on a type.
- `Query.user(id:)` — an argument on a field.
- `@deprecated` — a directive.
- `@deprecated(reason:)` — an argument on a directive.
These are not just syntax. The spec defines them formally so that linters, schema-diff tools, performance analytics, and automated review systems can all agree on what they're talking about. Imagine a CI pipeline that says "field User.email was made nullable; here are the 14 client operations affected" — schema coordinates are what makes that report mechanical instead of bespoke.
Descriptions on executable documents
Until now, descriptions were a schema-side thing. The new edition lets executable documents — your queries, mutations, and fragments — carry descriptions too:
"""Fetch the user's billing summary for the current month.
Used by the dashboard widget. Cached at the gateway for 60s.
"""
query DashboardSummary($userId: ID!) {
user(id: $userId) {
activeSubscriptions
upcomingInvoice {
total
dueDate
}
}
}Why this matters:
- Humans see intent and constraints in the document itself, not in a sibling README.
- LLM-assisted refactors can read the description before deciding how to modify the query.
- Operation registries (Apollo Studio, GraphQL Hive) can surface descriptions in search results.
The mechanism is small but the cultural shift it enables — operations are documents, not throwaway strings — is worth the change.
Richer deprecation
Earlier specs limited @deprecated to a few schema locations. The September 2025 edition extends it to:
- Input fields — mark a single input field deprecated without retiring the whole input.
- Arguments — deprecate an argument and let new clients omit it.
- Enum values — already worked in practice; now formally specified.
Deprecation reasons can be longer and richer, and tools can lint queries that still use deprecated bits. For an API at any reasonable scale, this is the difference between "we have a deprecation policy" and "we have a deprecation policy that's actually enforced".
Full Unicode
The grammar accepts the full Unicode range in identifiers and string literals. Practical implications:
- Schemas can use non-ASCII names where the team's language has them (
型,Über, etc.) without encoding tricks. - String literals carry emoji and complex graphemes correctly.
- Codegen tools no longer need ad-hoc transliteration.
It's a small spec change with outsized impact for non-English-speaking teams.
Execution semantics, clarified
Several execution rules had implicit dependencies on implementation details. The new edition makes them explicit:
- Field-merging rules — when the same field appears multiple times in a selection set, the spec is now exact about how the results merge.
- Defer/stream — incremental delivery is described in normative terms (the reference implementation already supported it experimentally).
- Error handling — null propagation and partial-result semantics are clarified, which matters for clients that try to render successful parts of a partial response.
These changes don't usually surface in day-to-day query writing; they surface when two implementations disagree about edge cases and a customer hits the seam.
Why "AI-first" gets named in the announcement
The blog post is unusually direct about LLM clients as a target audience. Three connections:
- Predictable validation.
@oneOfand richer deprecation reduce the number of "the schema technically allows X but will fail at runtime" cases that confuse code generators and prompt-driven clients. - Self-describing documents. Descriptions on operations let an LLM read intent without external context.
- Stable coordinates. Tools that explain "you sent a query that hit deprecated field
User.legacyEmail" are easier to build with formal coordinates.
The community is increasingly designing schemas that read well to a model, not just to a human. The September 2025 edition codifies the patterns that worked.
Adoption path
This is a non-breaking edition. Existing schemas remain valid. To adopt the new features:
- Servers — upgrade to a runtime that implements the new edition (graphql-js v17, Apollo Server, Yoga, Mercurius all shipped support during late 2025 / early 2026).
- Clients — most updates are transparent; codegen tools that update to the new edition emit better types automatically.
- Tools — linters and analytics that adopt schema coordinates can be wired into CI.
If you're on the October 2021 edition, there's no rush — but the next time you upgrade your server, opt in.
Tooling impact
The September 2025 edition is the first edition designed with the tooling ecosystem as a first-class audience, not an afterthought. Concrete improvements you'll notice in the next year:
- Schema linters —
graphql-eslint,graphql-schema-linter,graphql-inspector, andgraphqurlall use schema coordinates internally. Rule definitions and diagnostic output get more precise. - Codegen —
graphql-code-generator,@graphql-codegen/typescript,apollo-android,apollo-ios, and the Relay compiler emit better types for@oneOf, deprecated arguments, and operations with descriptions. - API explorers — Apollo Studio, GraphiQL, GraphQL Playground, and Altair render the new metadata (parent tags, deprecated arguments, executable-document descriptions) in their UIs.
- Testing tools —
graphql-toolsand similar frameworks pick up validation logic for the new constructs without consumers writing custom rules. - Observability — Apollo Studio and GraphQL Hive can attribute traces and metrics to schema coordinates, which makes "what's the slowest field?" or "which clients use deprecated argument X?" reports trivial to build.
The cumulative effect: the tooling stack moves from "knows about GraphQL" to "knows about this schema, in formal terms".
What didn't make this edition
A few notable items from the working group's queue that didn't make September 2025:
- Federation in core. Apollo Federation remains a separate spec layered on top.
- Streaming defaults.
@defer/@streamare documented but stay opt-in and require a separate execution path. - Subscription transport. The wire protocol for subscriptions is still implementation-defined;
graphql-wsis the de facto standard but isn't in the spec. - Schema diffing. Coordinate-based diff semantics are documented informally; a normative diff algorithm is on the roadmap.
These will likely land in subsequent editions. The cadence is open — September 2025 is the first dated edition since 2021, and the working group has signalled a preference for shorter cycles going forward.
Where this connects
The companion post on [@oneOf multi-option inputs](/blog/graphql-oneof-multioption-inputs) goes deeper into the directive itself; the graphql-js v17 release post covers the reference implementation that ships the new edition; the Apollo Router 2.14 post covers the federation gateway that mediates between subgraphs and clients.
References
- Canonical text: spec.graphql.org/September2025
- Changelog: graphql-spec September2025.md
- Announcement: graphql.org/blog
Source / further reading: GraphQL blog (Lee Byron)