Docs
Try Apollo Studio

What's new in Federation 2


📣 Apollo Federation 2 is now generally available! 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 supergraphs. You can probably move your existing supergraph 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.

    • Many subgraph-compatible libraries do not yet automatically define certain directives that are new in Federation 2, such as @shareable. You can define these directives manually to use them in your subgraph schemas.

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

Subgraph A
type Book {
title: String!
author: String!
}
Subgraph B
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

Subgraph A
type Book @shareable {
title: String!
author: String!
}
Subgraph B
type Book @shareable {
title: String!
author: String # Nullable
isbn: 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 Differing shared fields.

Enums, unions, and interfaces

In Federation 2, enum, union, and interface definitions can differ between subgraphs. For details, see Merging types from multiple subgraphs.

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

Products (originating)
type Product @key(fields: "id") {
id: ID!
name: String!
price: Int
}
Inventory (extending)
extend type Product @key(fields: "id") {
id: ID! @external
inStock: 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

Products
type Product @key(fields: "id") {
id: ID!
name: String!
price: Int
}
Inventory
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

Products
type Product @key(fields: "id") {
id: ID!
name: String! @shareable
price: Int
}
Inventory
type Product @key(fields: "id") {
id: ID!
name: String! @shareable
inStock: 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 define a reference resolver for that entity.

For example:

Fed. 2

Products
type Product @key(fields: "id") {
id: ID!
name: String!
price: Int
}
Reviews
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 unique fields to Product, so it doesn't need to define a reference resolver for it. Therefore, the "stub" definition of Product in the Reviews subgraph can include resolvable: false.

For more information, see Referencing an entity without contributing fields.

Migrating fields

Federation 2 introduces the @override directive, which helps you safely migrate entity fields between subgraphs with managed federation:

Payments subgraph
type Bill @key(fields: "id") {
id: ID!
amount: Int!
}
type Payment {
# ...
}
Billing subgraph
type Bill @key(fields: "id") {
id: ID!
amount: Int! @override(from: "Payments")
}

For details, see Entity migration.

Interfaces implementing interfaces

Federation 1 composition incorrectly fails if an interface type implements another interface. This issue is resolved in Federation 2:

Fed. 2

interface Media {
title: String!
}
interface Book implements Media {
title: String!
author: String!
}
Edit on GitHub
Previous
Introduction
Next
🚚 Moving your graph