What's new in the Federation 2 preview
⚠️ Apollo Federation 2 is in public preview. It is not yet feature-complete, and breaking changes might occur between this release and general availability. Learn about release stages.
Apollo Federation 2 provides developer experience improvements to the original specification for Apollo Federation (called Federation 1 in these docs). If your organization has an existing Federation 1 graph, this article summarizes the upcoming benefits of moving to Federation 2.
If you're just getting started with Federation, check out the Quickstart.
What isn't changing?
Before covering what's new, here's what isn't changing in Federation 2:
Most importantly, Federation 2 is backward compatible with most Federation 1 graphs. You can probably move your existing graph to use Federation 2 composition without making any changes.
- Graphs that do require changes are graphs that should cause composition errors, but Federation 1 fails to detect them. Learn more.
- To take full advantage of Federation 2 features, you do need to make some changes to your subgraph schemas, but you can make these changes incrementally at your convenience. See Moving to Apollo Federation 2.
Subgraph servers have no additional requirements. Any subgraph-compatible library is automatically compatible with Federation 2.
More flexible composition
Federation 2 improves the flexibility and independence of your subgraph schemas. New composition logic is more flexible compared to Federation 1, meaning teams can more confidently build out their subgraphs or migrate functionality between subgraphs.
Let's look at some examples!
Value types
In Federation 1, multiple subgraphs can define the same type, but those definitions must all be identical. These identical shared types are called value types:
Fed. 1
type Book {title: String!author: String!}
type Book {title: String!author: String!}
In Federation 2, this "identical definition" constraint is removed. Value types and their fields can be shared across subgraphs, even if certain details differ between definitions.
For details, see the sections below, along with Value types.
Objects
In Federation 2, an object type can be shared between subgraphs like so:
Fed. 2
type Book @shareable {title: String!author: String!}
type Book @shareable {title: String!author: String # Nullableisbn: String! # Not in A}
The two Book
type definitions above differ in terms of the fields they include and the nullability of those fields. Notice also the new @shareable
directive, which is required to indicate that a field can be resolved by multiple subgraphs.
Marking a type as @shareable
(as with Book
above) is equivalent to marking all of its fields as @shareable
.
This flexibility is especially helpful when an organization has multiple standalone GraphQL APIs that they want to unify with federation. Such APIs often share some types, and this added flexibility reduces the work required to compose their schemas successfully.
Valid shared field differences between subgraphs
- The return type of a shared field can vary in nullability (
String
/String!
). - Types can omit fields that are included in other subgraphs, as long as every field in your supergraph is always resolvable. (For details, see Rules of composition.)
For details on how these field differences are handled, see Sharing types.
Enums, unions, and interfaces
In Federation 2, enum
, union
, and interface
definitions can differ between subgraphs. For details, see Enums, unions, and interfaces.
Entities
Federation 2 introduces subtle but powerful changes to entities.
Originating subgraphs
In Federation 1, an entity originates in one subgraph and is then extended in other subgraphs:
Fed. 1
type Product @key(fields: "id") {id: ID!name: String!price: Int}
extend type Product @key(fields: "id") {id: ID! @externalinStock: Boolean!}
In Federation 2, entities do not have an "originating subgraph." Instead, each subgraph can define an entity and contribute fields to it:
Fed. 2
type Product @key(fields: "id") {id: ID!name: String!price: Int}
type Product @key(fields: "id") {id: ID!inStock: Boolean!}
For details, see Contributing entity fields.
Shared entity fields
In Federation 1, each entity field is resolved by exactly one subgraph (unless it's a @key
field or part of a @provides
directive). In Federation 2, multiple subgraphs can resolve the same entity field if they all mark it with the @shareable
directive:
Fed. 2
type Product @key(fields: "id") {id: ID!name: String! @shareableprice: Int}
type Product @key(fields: "id") {id: ID!name: String! @shareableinStock: Boolean!}
For more information, see Resolving another subgraph's field.
Changes to @key
Federation 2 adds a new optional argument to the @key
directive: resolvable
. You can set this argument to false
to indicate that a particular subgraph doesn't resolve any fields of a particular entity.
For example:
Fed. 2
type Product @key(fields: "id") {id: ID!name: String!price: Int}
type Product @key(fields: "id", resolvable: false) {id: ID!}type Review {product: Product!score: Int!}
In this case, the Reviews subgraph references the Product
entity by using it as the return type for Review.product
. However, the subgraph doesn't contribute any fields to the entity. Therefore, the "stub" definition of Product
in the Reviews subgraph needs to include only the @key
field for Product
(id
in this case) and indicate that it can't resolve any other fields.
For more information, see Referencing an entity without contributing fields.
Interfaces implementing interfaces
Federation 1 composition incorrectly fails if an interface type implements another interface type. This issue is resolved in Federation 2:
Fed. 2
interface Media {title: String!}interface Book implements Media {title: String!author: String!}