Docs
Launch Apollo Studio

Moving to Apollo Federation 2


⚠️ Until Federation 2 is generally available, do not move business-critical graphs to Federation 2. Learn about release stages.

This article describes how to move an existing federated graph to Apollo Federation 2. If you haven't yet, see what's new in Federation 2.

There are two high-level phases for moving to Federation 2:

  1. Use Federation 2 composition logic with your unmodified Federation 1 subgraph schemas.
  2. Modify your Federation 1 subgraph schemas to convert them to true Federation 2 subgraph schemas.

Phase 1 requires very few changes, and it's straightforward to move back to Federation 1 after making them. However, Phase 2 requires schema changes that remove backward compatibility with Federation 1. Because of this, we strongly recommend moving a test instance of your graph to Federation 2 first.

Phase 1: Use new composition logic

Update @apollo/gateway

Update your gateway's @apollo/gateway library to version 2.0.0-preview.7 or later. This enables your gateway to interact with supergraph schemas composed with Federation 2 logic.

You can install the latest Federation 2 gateway with the following command:

npm install @apollo/gateway@latest-2

These updated versions of @apollo/gateway continue to support Federation 1, so you can deploy this update without breaking your existing graph.

Configure your composition method

Federation 2 uses more flexible rules for schema composition. Follow the instructions for your current composition method:

Phase 2: Modify subgraph schemas

Your unmodified Federation 1 graph is now using Federation 2 composition! The natural next question is, "What does this change about my graph's behavior?" And right now, the answer is: nothing!

If your graph is not successfully composing with Federation 2, see Breaking changes for the most common causes.

If you want to take full advantage of Federation 2 features like improved control for type sharing, you now need to make some changes to your subgraph schemas.

You can update your subgraph schemas one at a time! The steps below describe how to modify a single subgraph schema for Federation 2, and you can perform these steps for a given subgraph whenever's convenient for your team.

Opt in to Federation 2

First, add the following definition to your subgraph schema:

extend schema
@link(url: "https://specs.apollo.dev/federation/v2.0",
import: ["@key", "@requires", "@shareable", "@provides", "@external"])

This definition identifies a schema as a true Federation 2 schema. Without this definition, the composition process assumes a subgraph schema is a Federation 1 schema, and it applies intelligent defaults to support backward compatibility.

If your subgraphs use Apollo Server and the @apollo/subgraph library, also update @apollo/subgraph like so:

npm install @apollo/subgraph@latest-2

This adds built-in support for new federation directives, such as @shareable.

Add schema definitions to non-Apollo subgraphs

During this preview, only Apollo Server using @apollo/subgraph adds some required definitions to your subgraph schemas automatically. If you're using any other supported subgraph libraries, you need to add the following definitions to those subgraph schemas:

We'll be working with library maintainers to help automatically add these schema definitions in libraries besides @apollo/subgraph.

Mark all value types as @shareable

By default in Federation 2, most schema fields are resolvable by only a single subgraph. In Federation 1, this is not true for value types:

Fed. 1 (invalid in Fed. 2)

Subgraph A
type Position {
x: Int!
y: Int!
}
Subgraph B
type Position {
x: Int!
y: Int!
}

For both subgraphs to resolve the above fields in Federation 2, the @shareable directive is required in both schemas:

Fed. 2

Subgraph A
type Position {
x: Int! @shareable
y: Int! @shareable
}
Subgraph B
type Position {
x: Int! @shareable
y: Int! @shareable
}

You can also apply @shareable directly to a type definition (such as Position above). This is equivalent to applying @shareable to all of that type's fields.

For more details, see Value types.

Update entity definitions

Federation 2 introduces subtle but powerful changes to entities. These changes require corresponding updates to their definitions in your subgraph schemas.

Remove unnecessary syntax

In Federation 1, an entity originates in one subgraph, and then other subgraphs extend the entity to add fields:

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 no longer 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!
}

Note the following in the Federation 2 subgraphs above:

  • The Inventory subgraph no longer extends the Product entity.
  • The Inventory subgraph no longer marks the Product.id field as @external.
    • The @external directive is no longer required for @key fields, but it is still required for @requires and @provides.
  • Both subgraphs can resolve Product.id, even though it isn't marked as @shareable!
    • Unlike most fields, @key fields such as Product.id are @shareable by default. This is necessary for @key fields, because the gateway uses them to associate data from different subgraphs with the same object.

Mark @provides fields as @shareable

The @provides directive enables a subgraph to resolve a particular field only for specific query paths. It's supported in Federation 2 as it is in Federation 1.

However, if a subgraph @provides a particular field, that field must be marked as @shareable in each subgraph where it's always resolvable:

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! @external
inStock: Boolean!
}
type Query {
outOfStockProducts: [Product!]! @provides(fields: "name")
}

Here, Query.outOfStockProducts in the Inventory subgraph @provides the Product.name field. Therefore, that field must be marked as @shareable in the Products subgraph (and @external in the Inventory subgraph, as in Federation 1). Otherwise, a composition error occurs.

Modify @keys for entity stubs

In certain cases, a subgraph references an entity without contributing any fields to it. In Federation 1, these cases look like the following:

Fed. 1

Products
type Product @key(fields: "id") {
id: ID!
name: String!
price: Int
}
Reviews
type Product @key(fields: "id") {
id: ID!
}
type Review {
product: Product!
score: Int!
}

The Reviews subgraph above uses Product as the return type of the Review.product field, so it needs to define a "stub" of the Product entity. This stub includes just enough information to identify a unique instance.

In Federation 2, stubs like Product should include resolvable: false in their @key arguments, like so:

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!
}

Setting resolvable: false is a helpful hint to the gateway to indicate that a subgraph references an entity without contributing fields to it.

Previous
☀️ New in the preview
Next
⬅️ Backward compatibility