GraphQL Federation Gets a Vendor-Neutral Specification (and a New Name)

For most GraphQL developers, "federation" has meant Apollo Federation: a set of directives, a _entities field in every service, and a router that stitches it all together. Other vendors built gateways that are compatible with Apollo's design. Under the GraphQL Foundation, a working group has worked since 2022 on a vendor-neutral specification for the same job. On 21 September 2026 that specification got a new name. The Composite Schemas specification is now the GraphQL Federation specification.
Why a Foundation Specification
The roadmap states the mission in one sentence:
Provide a specification that allows to build GraphQL Gateways and GraphQL composition tooling with different implementations and technology stacks to interact freely if GraphQL composition tooling and GraphQL gateways are compliant.
Until now, the most widely used rules for composition and execution came from one vendor's design, and other gateways stayed compatible by following it. A shared specification gives every vendor the same written rules. The goal is that any compliant composition tool can produce the input for any compliant gateway, the same way any compliant GraphQL server can answer any compliant client.
Michael Staib proposed the new name at the GraphQL working group meeting on 6 August 2026, and his PR #237 made the change on 21 September. The repository moved to graphql/graphql-federation-spec, and the meetings continue in the Composite Schemas working group. The draft changelog for the GraphQL specification's September 2026 edition, opened on 24 September, describes the effort as "a strong collaboration between many vendors".
Four Words to Know
The Overview introduces the vocabulary that the rest of the specification uses:
- Source schema: the schema of one service. Apollo Federation calls this a subgraph.
- Composite schema: the single schema that clients see, built from all the source schemas. Apollo Federation calls this the supergraph.
- Execution schema: an intermediate schema that composition produces for the gateway, with directives that describe how to execute requests.
- Distributed GraphQL executor: the component that runs a client's request against the composite schema by calling the source schemas, usually inside a gateway.
The Overview also states what clients should notice: the composite schema "presents itself as a regular GraphQL schema", and all observable behavior is the same as the GraphQL specification describes.
Entities Without _entities
The most visible design difference from Apollo Federation is how the gateway fetches an object from a second service. In Apollo Federation, subgraphs implement a special _entities(representations: [_Any!]!) field, and a federation library in each service answers it. The GraphQL Federation specification uses ordinary query fields instead, marked with @lookup.
Here is a movie split across two services. The movies service owns the title:
type Query {
movieById(id: ID!): Movie @lookup
}
type Movie @key(fields: "id") {
id: ID!
title: String!
}
The reviews service owns the reviews, and it has its own lookup field for movies:
type Query {
movieById(id: ID!): Movie @lookup @internal
}
type Movie @key(fields: "id") {
id: ID!
reviews: [Review!]!
}
type Review {
stars: Int!
text: String!
}
Three directives do the work:
@keydeclares thatMovieis an entity and thatididentifies it in every source schema. The Entities and Identity section calls this the identity's "comparison" half.@lookupmarks a field that the executor can call to fetch aMovieby that key. The specification calls this the "recall" half.@internalkeeps the reviews service's lookup out of the client-facing schema. The executor can still call it.
Composition merges the two into the schema that clients see:
type Query {
movieById(id: ID!): Movie
}
type Movie {
id: ID!
title: String!
reviews: [Review!]!
}
type Review {
stars: Int!
text: String!
}
When a client asks for movieById(id: "1") { title reviews { stars } }, the executor asks the movies service for the title, and then calls the internal movieById(id: "1") on the reviews service for the reviews. Both calls are normal GraphQL queries.
What This Means for a Spring Service
Because a lookup is an ordinary query field, a Spring for GraphQL application can serve the reviews schema above with a normal controller, without a federation library:
@Controller
public class ReviewController {
record Movie(String id) {}
record Review(int stars, String text) {}
@QueryMapping
public Movie movieById(@Argument String id) {
return new Movie(id);
}
@SchemaMapping
public List<Review> reviews(Movie movie) {
return List.of(new Review(5, "Still holds up."));
}
}
The schema file needs one more thing: graphql-java only accepts directives that the schema declares. We added the three declarations from the specification to the top of schema.graphqls, together with the FieldSelectionSet scalar that @key uses:
directive @key(fields: FieldSelectionSet!) repeatable on OBJECT | INTERFACE
directive @lookup on FIELD_DEFINITION
directive @internal on OBJECT | FIELD_DEFINITION
scalar FieldSelectionSet
Our first start on Spring Boot 4.2.0-M2 failed with Cannot invoke "graphql.schema.GraphQLScalarType.getCoercing()" because "scalarType" is null. graphql-java needs an implementation for every custom scalar, including one that only appears in directive arguments. Registering FieldSelectionSet as a string scalar solved it:
@Configuration
public class FederationScalarConfig {
@Bean
public RuntimeWiringConfigurer federationScalars() {
GraphQLScalarType fieldSelectionSet = GraphQLScalarType.newScalar()
.name("FieldSelectionSet")
.coercing(Scalars.GraphQLString.getCoercing())
.build();
return (wiringBuilder) -> wiringBuilder.scalar(fieldSelectionSet);
}
}
After that, the service answered the lookup the gateway would send:
{"data":{"movieById":{"id":"1","reviews":[{"stars":5,"text":"Still holds up."}]}}}
Composition needs each service's SDL file, with its directives, because standard introspection does not expose directives applied to fields and types.
The Directives at a Glance
Section 2 defines ten directives for source schemas. Developers who know Apollo Federation will recognize several of the names:
| Directive | What it does |
|---|---|
@key | Declares the fields that identify an entity across source schemas |
@lookup | Marks a field the executor can call to fetch an entity by a key |
@internal | Hides a type or field from the composite schema, inside one source schema only |
@inaccessible | Hides a type system member from the composite schema, even if other source schemas expose it |
@shareable | Allows more than one source schema to resolve the same field |
@is | Maps a lookup argument to a field on the returned type when the names differ |
@require | Marks an argument whose value the executor fetches from another source schema |
@provides | Says a field can return some fields of its type directly, as an optimization |
@external | Marks a field that this source schema references and another one resolves |
@override | Moves a field from one source schema to another |
One row behaves differently from its Apollo Federation relative. @require sits on an argument, while Apollo's @requires sits on a field, so the data a field needs from another service arrives as a normal argument. Sharing works the way Apollo Federation 2 users expect. The specification says "only a single source schema is allowed to contribute a particular field to an object type" unless the field is marked @shareable. Key fields are shareable without a mark.
The rules are still changing. In August 2026 the working group merged three changes:
- lookups must resolve every possible return type (#229)
@requireis forbidden on lookup fields (#230)- "
@providesis an optimization, never a requirement" (#231)
Who Implements It
At least two gateways describe themselves as implementations in September 2026:
- Hot Chocolate Fusion for .NET, whose documentation says "Fusion implements the GraphQL Composite Schemas specification".
- feddi Gateway for the JVM, built on graphql-java and released under the Apache 2.0 license. Its website names "Andi Marek, creator of GraphQL Java" as the person who built it. The repository was created in April 2026 and does not have a tagged release yet.
For Java developers, feddi means the whole path, from Spring for GraphQL source schemas to the gateway, can run on the JVM. Because the specification is at Stage 0, expect both gateways to change along with it.
Should You Switch?
If you run Apollo Federation in production today, this specification does not give you a reason to move yet. It is at Stage 0, and Apollo Federation is a mature system with years of production use.
If you are designing new services, one idea from the specification is useful now: entity lookups as ordinary query fields. A service built that way stays an ordinary GraphQL server that you can test with ordinary queries. It also makes a later move to a specification-based gateway easier, whichever vendor you choose.
To try it, start with our January post on federation for the general ideas, then compose two small source schemas with one of the gateways above.
This post was composed from several source schemas: one specification, a handful of pull requests and two gateway READMEs. Every fact in it is @shareable. This joke should probably have been marked @internal.
Sources
- GraphQL Federation specification - the repository, with the status, the roadmap and the specification text
- Published specification versions - the rendered drafts of the specification
- graphql-federation-spec PR #237 - the rename from Composite Schemas to GraphQL Federation
- Composite Schemas working group - agendas, notes and recordings of the meetings
- Hot Chocolate Fusion documentation - the .NET implementation
- feddi Gateway - the JVM implementation built on graphql-java
- Apollo Federation subgraph specification - the
_entitiesfield and the directives this post compares against