Docs
Try Apollo Studio

Federation-specific GraphQL directives


Apollo Federation defines a collection of directives that you use in your subgraph schemas to enable certain features.

Importing directives

To use federated directives in a Federation 2 subgraph schema, apply the @link directive with the following format to the schema type:

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

You can apply this directive to your existing schema declaration if you have one, or to a new extend schema declaration (as shown above).

Modify the import array to include whichever federated directives your subgraph schema uses. The example above imports the @key and @shareable directives (which are used most commonly).

Make sure to include the @ in each directive name!

Renaming directives

If an imported directive's default name matches one of your own custom directives, you can rename the imported directive with the following syntax:

extend schema
@link(url: "https://specs.apollo.dev/federation/v2.0",
import: [{ name: "@key", as: "@primaryKey"}, "@shareable"])

This example subgraph schema uses @primaryKey for the federated directive usually named @key.

Namespaced directives

If you don't import a particular directive from a linked spec, you can still use that directive in your subgraph schema. However, that directive is namespaced with a prefix:

extend schema
@link(url: "https://specs.apollo.dev/federation/v2.0",
import: ["@key"])
type Book @federation__shareable {
title: String!
}

In the example above, @shareable is not imported from the federation spec. Therefore, it is available as @federation__shareable.

The default namespace prefix for a @linked directive is the name of its associated specification (indicated by the penultimate component of url), plus two underscores (__). For Apollo Federation directives, this prefix is federation__.

You can customize a particular specification's namespace prefix by providing the as argument to @link:

extend schema
@link(url: "https://specs.apollo.dev/federation/v2.0",
as: "fed")
type Book @fed__shareable {
title: String!
}

As shown, custom namespace prefixes also end in two underscores.

directive @link(
url: String!,
as: String,
for: link__Purpose,
import: [link__Import]
) repeatable on SCHEMA

Links definitions from an external specification to this schema. Every Federation 2 subgraph uses the @link directive to import the other federation-specific directives described in this article (see the syntax in Importing directives).

For more information on @link, see the official spec.

Managing types

@key

directive @key(fields: FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE

Designates an object type as an entity and specifies its key fields (a set of fields that the subgraph can use to uniquely identify any instance of the entity).

type Product @key(fields: "id") {
id: ID!
name: String!
price: Int
}

You can apply multiple @key directives to a single entity (to specify multiple valid sets of key fields), if your subgraph library supports repeatable directives:

type Product @key(fields: "upc") @key(fields: "sku") {
upc: ID!
sku: ID!
name: String
}

To check whether your subgraph library supports repeatable directives, see the repeatable @key item in Federation-compatible subgraph implementations.

⚠️ Do not apply @key to interface definitions. The INTERFACE location is included in this definition for backward compatibility with Federation 1 subgraphs. Currently, applying @key to an interface has no effect in any version of federation, and Federation 2 subgraphs produce a composition error to emphasize this.

Arguments

Name /
Type
Description
fields

Required. A GraphQL selection set (provided as a string) of fields and subfields that contribute to the entity's primary key.

Examples:

  • "id"
  • "username region"
  • "name organization { id }"

See also Advanced @keys.

resolvable

Boolean

If false, indicates to the graph router that this subgraph doesn't define a reference resolver for this entity. This means that router query plans can't "jump to" this subgraph to resolve fields that aren't defined in another subgraph.

Most commonly, you set this to false when referencing an entity without contributing fields.

The default value is true.

@extends

directive @extends on OBJECT | INTERFACE

Indicates that an object or interface definition is an extension of another definition of that same type.

⚠️ If your subgraph library supports GraphQL's built-in extend keyword, do not use this directive! Instead, use extend.

This directive is for use with GraphQL subgraph libraries that do not support the extend keyword. Most commonly, these are subgraph libraries that generate their schema programmatically instead of using a static .graphql file.

Note that Federation 2 does not require any use of type extensions.

In Federation 1, every subgraph must extend the Query and Mutation types (if it defines them), and entities are extended in every subgraph that defines them except their originating subgraph.

Managing shared fields

@shareable

directive @shareable on FIELD_DEFINITION | OBJECT

Indicates that an object type's field is allowed to be resolved by multiple subgraphs (by default in Federation 2, object fields can be resolved by only one subgraph).

type Position {
x: Int! @shareable
y: Int! @shareable
}

If applied to an object type definition, all of that type's fields are considered @shareable:

type Position @shareable {
x: Int!
y: Int!
}

If a field is marked @shareable in any subgraph, it must be marked as either @shareable or @external in every Federation 2 subgraph that defines it.

If a Federation 2 supergraph includes a Federation 1 subgraph, all value types in the Federation 1 subgraph are automatically considered @shareable by the Federation 2 composition algorithm.

If a field is included in an entity's @key directive, that field is automatically considered @shareable and the directive is not required in the corresponding subgraph(s).

See also Value types in Apollo Federation and Resolving another subgraph's field.

@inaccessible

directive @inaccessible on FIELD_DEFINITION | INTERFACE | OBJECT | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION

Indicates that a definition in the subgraph schema should be omitted from the gateway's API schema, even if that definition is also present in other subgraphs. This means that the field is not exposed to clients at all.

Common use cases for @inaccessible include:

  • Avoiding composition errors while making staggered updates to a definition that's shared across multiple subgraphs (such as a value type)
  • Using a private field as part of an entity's @key without exposing that field to clients
Subgraph A
type Position @shareable {
x: Int!
y: Int!
z: Int! @inaccessible
}
Subgraph B
type Position @shareable {
x: Int!
y: Int!
# Subgraph is not yet updated
}

Often when you add a field to a value type in one subgraph, composition fails because that field isn't resolvable in other subgraphs. With @inaccessible, you can preserve composition while adding the field to your remaining subgraphs. When the rollout is complete, you can remove the directive and begin using the field.

An @inaccessible field or type is not omitted from the supergraph schema, so the graph router still knows it exists (but clients can't include it in operations). This is what enables the graph router to use an @inaccessible field as part of an entity's @key when combining entity fields from multiple subgraphs.

If a type is marked @inaccessible, all fields that return that type must also be marked @inaccessible. Otherwise, a composition error occurs.

For more information, see Using @inaccessible.

@override

directive @override(from: String!) on FIELD_DEFINITION

Indicates that an object field is now resolved by this subgraph instead of another subgraph where it's also defined. This enables you to migrate a field from one subgraph to another.

Products subgraph
type Product @key(fields: "id") {
id: ID!
inStock: Boolean!
}
Inventory subgraph
type Product @key(fields: "id") {
id: ID!
inStock: Boolean! @override(from: "Products")
}

In the example above, we're migrating the Product.inStock field from the Products subgraph to the Inventory subgraph. The composed supergraph schema indicates that Product.inStock is resolved by the Inventory subgraph but not the Products subgraph, even though the Products subgraph also defines the field.

You can apply @override to a @shareable field. If you do, only the subgraph you provide in the from argument no longer resolves that field. Other subgraphs can still resolve the field.

Only one subgraph can @override any given field. If multiple subgraphs attempt to @override the same field, a composition error occurs.

For more information, see Migrating entities and fields.

Arguments

Name /
Type
Description
from

String

Required. The name of the other subgraph that no longer resolves the field.

  • If you're performing composition with managed federation, this must match the name of the subgraph in Apollo Studio.
  • If you're performing composition with the Rover CLI, this must match the name of the subgraph in the YAML config file you provide to rover supergraph compose.

Referencing external fields

@external

directive @external on FIELD_DEFINITION

Indicates that this subgraph usually can't resolve a particular object field, but it still needs to define that field for other purposes.

This directive is always used in combination with another directive that references object fields, such as @provides or @requires.

Inventory subgraph
type Product @key(fields: "id") {
id: ID!
name: String! @external
inStock: Boolean!
}
type Query {
outOfStockProducts: [Product!]! @provides(fields: "name")
discontinuedProducts: [Product!]!
}

This example subgraph usually can't resolve the Product.name field, but it can at the Query.outOfStockProducts query path (indicated by the @provides directive).

@provides

directive @provides(fields: FieldSet!) on FIELD_DEFINITION

Specifies a set of entity fields that a subgraph can resolve, but only at a particular schema path (at other paths, the subgraph can't resolve those fields).

If a subgraph can always resolve a particular entity field, do not apply this directive.

Using this directive is always an optional optimization. It can reduce the total number of subgraphs that your graph router needs to communicate with to resolve certain operations, which can improve performance.

Inventory subgraph
type Product @key(fields: "id") {
id: ID!
name: String! @external
inStock: Boolean!
}
type Query {
outOfStockProducts: [Product!]! @provides(fields: "name")
discontinuedProducts: [Product!]!
}

This example subgraph can resolve Product.name for products returned by Query.outOfStockProducts but not Query.discontinuedProducts.

If a subgraph @provides an entity field:

  • The subgraph must define that field and mark it as @external, as shown above with Product.name.
  • The entity field must be marked as either @shareable or @external in every subgraph that defines it.
  • The entity field must be marked as @shareable in at least one other subgraph (i.e., there's at least one subgraph that can always resolve the field).

Otherwise, a composition error occurs.

For more information, see Using @provides.

Arguments

Name /
Type
Description
fields

Required. A GraphQL selection set (provided as a string) of object fields and subfields that the subgraph can resolve only at this query path.

Examples:

  • "name"
  • "name address"
  • "... on Person { name address }" (valid for fields that return a union or interface)

@requires

directive @requires(fields: FieldSet!) on FIELD_DEFINITION

Indicates that the resolver for a particular entity field depends on the values of other entity fields that are resolved by other subgraphs. This tells the graph router that it needs to fetch the values of those externally defined fields first, even if the original client query didn't request them.

Shipping subgraph
type Product @key(fields: "id") {
id: ID!
size: Int @external
weight: Int @external
shippingEstimate: String @requires(fields: "size weight")
}

The example subgraph above resolves a Product object's shippingEstimate field, but it requires the product's size and weight to do so. Because these two fields are resolved by a different subgraph, they're marked as @external.

If a subgraph @requires an entity field, the subgraph must define that field and mark it as @external, as shown above with Product.size and Product.weight. Otherwise, a composition error occurs.

See also Contributing computed entity fields.

Arguments

Name /
Type
Description
fields

Required. A GraphQL selection set (provided as a string) of @external object fields and subfields that this field requires.

Examples:

  • "name"
  • "name address"
  • "name organization { id }"

Managing custom directives

@composeDirective

directive @composeDirective(name: String!) repeatable on SCHEMA

Indicates to composition that all uses of a particular custom directive in the subgraph schema should be preserved in the supergraph schema (by default, composition omits most directives from the supergraph schema).

extend schema
@link(url: "https://specs.apollo.dev/link/v1.0")
@link(url: "https://specs.apollo.dev/federation/v2.1", import: ["@composeDirective"])
@link(url: "https://myspecs.dev/myDirective/v1.0", import: ["@myDirective", { name: "@anotherDirective", as: "@hello" }])
@composeDirective(name: "@myDirective")
@composeDirective(name: "@hello")

This directive has the following requirements:

  • The directive to preserve must be defined and imported from a core specification via the @link directive.
  • The specified directive name must match the name used for the directive in this subgraph.
    • If you use the as argument in your @link definition to modify the directive's name from its spec's default, provide the modified name, not the default name.
  • If multiple subgraphs import and use the directive:
    • The name used for the directive must be identical in all of those subgraphs.
    • All of those subgraphs should use the same major version of the spec that defines the directive.

If any of these requirements is not met, composition fails.

If different subgraphs use different versions of a directive's corresponding spec, the supergraph schema uses whichever version number is highest among all subgraphs. Composition does not verify whether this version of the directive is compatible with subgraphs that use an earlier version.

Arguments

Name /
Type
Description
name

Required. The name (including the leading @) of the directive to preserve during composition.

Edit on GitHub
Previous
Composition
Next
Sharing types (value types)