Moving to Apollo Federation 2
Upgrade from Apollo Federation 1 to Federation 2
📣 If you haven't yet, see what's new in Federation 2.
You can (and should!) move your Apollo Federation 1 supergraph to Federation 2 incrementally, one component at a time. Your supergraph will work as expected after each step in the process, even while some of your subgraphs continue using Federation 1 schemas.
Each individual step of moving your supergraph has its own benefits, so it's useful to complete as many steps as you're ready to complete. You can always finish the rest later.
Here are the three steps for moving to Federation 2:
Upgrade your gateway to support Federation 2.
You can upgrade to either of the following:
The GraphOS Router , a high-performance precompiled executable (recommended)
Version 2.x of the
@apollo/gateway
library, along with version 4.x of Apollo Server
Begin composing your supergraph schema with Federation 2 composition logic.
Update your individual subgraphs to use Federation 2 features and directives.
As with all infrastructure changes, we strongly recommend completing each of these steps with a test instance of your supergraph before performing them in production.
Step 1: Upgrade your gateway
For your Federation 1 supergraph to support Federation 2, you first need to upgrade its gateway to one of the following:
The GraphOS Router. This is a high-performance, precompiled executable that is based on the Apollo Router Core and provides many benefits over the Node.js-based gateway.
We recommend moving to the GraphOS Router unless you've extended your Node.js gateway with functionality that the GraphOS Router doesn't currently support (this is uncommon).
Version 2.x of the
@apollo/gateway
library, with version 4.x of Apollo Server
@apollo/gateway
v2.x support Federation 1. You can upgrade to either without making any other changes to your Federation 1 supergraph, and it will work as expected.Moving to the GraphOS Router
To get started running the GraphOS Router, see the overview .
For guidance on moving to the GraphOS Router from your Node.js-based gateway, see this article .
Upgrading @apollo/gateway
and Apollo Server
The @apollo/gateway
library supports Federation 2 supergraph schemas in version 2.0.0
and later. These versions of @apollo/gateway
require version 16.0.0
or later of the graphql
library.
You can install updated versions of these libraries in your gateway project with the following command:
1npm install @apollo/gateway graphql
Apollo Server 3.x supports these updated library versions, however Apollo Server 3.x is deprecated. Therefore, we strongly recommend also upgrading your gateway to Apollo Server 4.
If you're still using Apollo Server 2.x, we recommend migrating to v3.x and then migrating to 4.x.
Step 2: Configure your composition method
Federation 2 uses a completely new method to compose supergraph schemas. This method is backward compatible with Federation 1 subgraph schemas, and it provides the following benefits even for Federation 1 subgraphs:
Helpful composition hints when schema definitions are inconsistent between your subgraphs
Support for interfaces implementing other interfaces (which Federation 1 composition doesn't support)
Follow the instructions below to configure whichever composition method(s) you currently use:
Managed federation with GraphOS
The Rover CLI
- Install the latest version of Rover using the appropriate command for your system:BashMacOS
1curl -sSL https://rover.apollo.dev/nix/latest | sh
BashWindows1iwr 'https://rover.apollo.dev/win/latest' | iex
- Open the YAML
--config
file you provide torover supergraph compose
and add the following line to the top:YAMLsupergraph-config.yaml1federation_version: 2
1rover supergraph compose --config ./supergraph.yaml
After you configure these changes, make sure your router is using your newly created Federation 2 supergraph schema. (If you're using managed federation, your router will fetch the new schema from Apollo automatically.)
Your Federation 1 subgraphs are now composed using Federation 2 composition. The natural next question is, "What does this change about the behavior of those subgraphs?" And until the next step, the answer is: nothing!
Step 3: Update individual subgraphs
Federation 2 provides powerful new features that require making some changes to your subgraphs. These features include:
Selectively sharing types and fields across subgraphs with
@shareable
Safely migrating fields from one subgraph to another with
@override
Hiding internal routing fields from graph consumers with
@inaccessible
The schema changes you make are not backward compatible with Federation 1, which means you won't be able to use Federation 1 composition anymore unless you revert those changes.
Update your subgraph library
To use new Federation 2 features and their associated directives, it's helpful to update your subgraph library to a version that automatically supports those directives.
If your subgraph uses Apollo Server and the
@apollo/subgraph
library, update@apollo/subgraph
to version2.0.0
or later like so:Bash1npm install @apollo/subgraph
If your subgraph uses another server library, check the compatibility table to see whether it supports Federation 2 directives yet. If it does, consult that library's documentation to determine which version you need to update to.
If your library doesn't support Federation 2 directives yet, you can still use that library with Federation 2 if the library lets you add custom directive definitions to your schema!
Opt in to Federation 2
Add the following definition to your subgraph schema:
1extend schema
2 @link(url: "https://specs.apollo.dev/federation/v2.0",
3 import: ["@key", "@shareable"])
This definition identifies a schema as a Federation 2 schema, and it import
s any federation-specific directives that the schema uses. Without this @link
definition, composition considers a schema to be a Federation 1 schema, and it applies certain default settings for backward compatibility.
import
array, such as @external
or @provides
.See all Federation-specific directives. Add directive definitions if needed
Currently, not all subgraph libraries provide built-in support for Federation 2 directives (such as @shareable
). If your library doesn't provide this support, you need to add the following directive definitions to your subgraph schema:
Click to expand
1# Required for all subgraph schemas
2scalar link__Import
3
4directive @link(
5 url: String!,
6 import: [link__Import],
7) repeatable on SCHEMA
8
9# Required if the corresponding directive is used
10directive @shareable on FIELD_DEFINITION | OBJECT
Definitions for all Federation 2 directives are available in this article . We work with library maintainers to help automatically add these schema definitions in as many subgraph libraries as possible.
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)
1type Position {
2 x: Int!
3 y: Int!
4}
1type Position {
2 x: Int!
3 y: Int!
4}
For both subgraphs to resolve the above fields in Federation 2, the @shareable
directive is required in both schemas:
Fed. 2
1type Position {
2 x: Int! @shareable
3 y: Int! @shareable
4}
1type Position {
2 x: Int! @shareable
3 y: Int! @shareable
4}
@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
1type Product @key(fields: "id") {
2 id: ID!
3 name: String!
4 price: Int
5}
1extend type Product @key(fields: "id") {
2 id: ID! @external
3 inStock: Boolean!
4}
In Federation 2, entities no longer have an originating subgraph. Instead, each subgraph can define an entity and contribute fields to it:
Fed. 2
1type Product @key(fields: "id") {
2 id: ID!
3 name: String!
4 price: Int
5}
1type Product @key(fields: "id") {
2 id: ID!
3 inStock: Boolean!
4}
Note the following in the Federation 2 subgraphs above:
The Inventory subgraph no longer
extend
s theProduct
entity.The Inventory subgraph no longer marks the
Product.id
field as@external
.Both subgraphs can resolve
Product.id
, even though it isn't marked as@shareable
!Unlike most fields,
@key
fields such asProduct.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
1type Product @key(fields: "id") {
2 id: ID!
3 name: String! @shareable
4 price: Int
5}
1type Product @key(fields: "id") {
2 id: ID!
3 name: String! @external
4 inStock: Boolean!
5}
6
7type Query {
8 outOfStockProducts: [Product!]! @provides(fields: "name")
9}
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 @key
s 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
1type Product @key(fields: "id") {
2 id: ID!
3 name: String!
4 price: Int
5}
1type Product @key(fields: "id") {
2 id: ID!
3}
4
5type Review {
6 product: Product!
7 score: Int!
8}
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
1type Product @key(fields: "id") {
2 id: ID!
3 name: String!
4 price: Int
5}
1type Product @key(fields: "id", resolvable: false) {
2 id: ID!
3}
4
5type Review {
6 product: Product!
7 score: Int!
8}
Setting resolvable: false
tells the gateway that a subgraph doesn't define a reference resolver for a particular entity. This is most common when referencing an entity without contributing fields to it .
You're done! You should now have a Federation 2 supergraph that composes successfully and takes full advantage of new federation features. If you encounter an issue, please let us know in the community forums .