Apollo Federation Directives
Reference for Apollo 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.3",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).
💡 TIP
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.3",import: [{ name: "@key", as: "@uniqueKey"}, "@shareable"])
This example subgraph schema uses @uniqueKey
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.3",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 @link
ed 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.3",as: "fed")type Book @fed__shareable {title: String!}
As shown, custom namespace prefixes also end in two underscores.
The @link
directiveSince 2.0
directive @link(url: String!,as: String,for: link__Purpose,import: [link__Import]) repeatable on SCHEMA
This directive 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
Since 1.0
directive @key(fields: FieldSet!, resolvable: Boolean = true) repeatable on OBJECT | INTERFACE
Designates an object type as an entity and specifies its key fields. Key fields are a set of fields that a subgraph can use to uniquely identify any instance of the entity.
type Product @key(fields: "id") {id: ID!name: String!price: Int}
💡 TIP
To learn best practices and advanced use cases for @key
, refer to the following guides:
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}
ⓘ NOTE
To check whether your subgraph library supports repeatable directives, see the repeatable @key
item in Federation-compatible subgraph implementations.
In Apollo Federation 2.3 and later, you can also apply @key
to interface
definitions to create entity interfaces. If you apply @key
to an interface
in earlier versions of Federation 2, a composition error occurs.
Arguments
Name / Type | Description |
---|---|
| Required. A GraphQL selection set (provided as a string) of fields and subfields that contribute to the entity's unique key. Examples:
See also Advanced |
| If Most commonly, you set this to The default value is |
@interfaceObject
Since 2.3
directive @interfaceObject on OBJECT
Indicates that an object definition serves as an abstraction of another subgraph's entity interface. This abstraction enables a subgraph to automatically contribute fields to all entities that implement a particular entity interface.
During composition, the fields of every @interfaceObject
are added both to their corresponding interface
definition and to all entity types that implement that interface.
Learn more about entity interfaces.
@extends
Since 1.0
directive @extends on OBJECT | INTERFACE
Indicates that an object or interface definition is an extension of another definition of that same type.
⚠️ CAUTION
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
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
Since 2.0
directive @shareable repeatable on FIELD_DEFINITION | OBJECT
ⓘ NOTE
@shareable
is only repeatable
in v2.2 and later.
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! @shareabley: 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.
ⓘ NOTE
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.
The @shareable
directive is about indicating when an object field can be resolved by multiple subgraphs. As interface fields are not directly resolved (their implementation is), @shareable
is not meaningful on an interface field and is not allowed (at least since federation 2.2; earlier versions of federation 2 mistakenly ignored @shareable
on interface fields).
@inaccessible
Since 2.0
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 router'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
ⓘ NOTE
Unlike with most directives, composition preserves uses of this directive in the generated supergraph schema. To preserve uses of other directives, see @composeDirective
.
Consequently, if you rename this directive, you must use the same name in every subgraph. Otherwise, a composition error occurs due to a naming mismatch.
type Position @shareable {x: Int!y: Int!z: Int! @inaccessible}
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 router still knows it exists (but clients can't include it in operations). This is what enables the 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
Since 2.0
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.
You can apply @override
to entity fields and fields of the root operation types (such as Query
and Mutation
).
type Product @key(fields: "id") {id: ID!inStock: Boolean!}
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 entity and root fields.
Progressive @override
Since 2.7
Progressive @override
is an Enterprise feature of the GraphOS Router and requires an organization with a GraphOS Enterprise plan. If your organization doesn't have an Enterprise plan, you can test it out by signing up for a free Enterprise trial.
Rolling out any change to a production subgraph, including field migration, risks degrading the performance of your graph. Rerouting all traffic from one subgraph to another all at once could overload the overriding subgraph.
The progressive @override
feature enables the gradual, progressive deployment of a subgraph with an @override
field. As a subgraph developer, you can customize the percentage of traffic that the overriding and overridden subgraphs each resolve for a field. You apply a label to an @override
field to set the percentage of traffic for the field that should be resolved by the overriding subgraph, with the remaining percentage resolved by the overridden subgraph. You can then monitor the performance of the subgraphs in Studio, resolve any issues, and iteratively and progressively increase the percentage until all traffic is resolved by the overriding subgraph.
To learn more, see the Incremental migration with @override
guide.
Arguments
Name / Type | Description |
---|---|
| Required. The name of the other subgraph that no longer resolves the field.
|
| This argument is available in Apollo Federation 2.7 and later. It is an Enterprise feature of the GraphOS Router and requires an organization with a GraphOS Enterprise plan. You can test it out by signing up for a free Enterprise trial. Optional. A string of arbitrary arguments. Supported in this release:
|
Controlling access
@authenticated
Since 2.5
This directive is an Enterprise feature of the GraphOS Router and requires an organization with a GraphOS Enterprise plan. If your organization doesn't have an Enterprise plan, you can test it out by signing up for a free Enterprise trial.
directive @authenticated onFIELD_DEFINITION| OBJECT| INTERFACE| SCALAR| ENUM
Indicates to composition that the target element is accessible only to the authenticated supergraph users. For more granular access control, see the @requiresScopes
directive below. Refer to the router article for additional details.
@requiresScopes
Since 2.5
This directive is an Enterprise feature of the GraphOS Router and requires an organization with a GraphOS Enterprise plan. If your organization doesn't have an Enterprise plan, you can test it out by signing up for a free Enterprise trial.
directive @requiresScopes(scopes: [[federation__Scope!]!]!) onFIELD_DEFINITION| OBJECT| INTERFACE| SCALAR| ENUM
Indicates to composition that the target element is accessible only to the authenticated supergraph users with the appropriate JWT scopes. Refer to the router article for additional details.
Arguments
Name / Type | Description |
---|---|
| Required. List of JWT scopes that must be granted to the user in order to access the underlying element data. |
@policy
Since 2.6
This directive is an Enterprise feature of the GraphOS Router and requires an organization with a GraphOS Enterprise plan. If your organization doesn't have an Enterprise plan, you can test it out by signing up for a free Enterprise trial.
directive @policy(policies: [[federation__Policy!]!]!) on| FIELD_DEFINITION| OBJECT| INTERFACE| SCALAR| ENUM
Indicates to composition that the target element is restricted based on authorization policies that are evaluated in a Rhai script or coprocessor. Refer to the router article for additional details.
Arguments
Name / Type | Description |
---|---|
| Required. List of authorization policies to evaluate. |
Referencing external fields
@external
Since 1.0
directive @external on FIELD_DEFINITION | OBJECT
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
.
type Product @key(fields: "id") {id: ID!name: String! @externalinStock: 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).
If applied to an object type definition, all of that type's fields are considered @external
:
type Position @external {x: Int!y: Int!}
@provides
Since 1.0
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 router needs to communicate with to resolve certain operations, which can improve performance.
type Product @key(fields: "id") {id: ID!name: String! @externalinStock: 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
.
ⓘ NOTE
If a subgraph @provides
an entity field:
- The subgraph must define that field and mark it as
@external
, as shown above withProduct.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 |
---|---|
| 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:
|
@requires
Since 1.0
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 router that it needs to fetch the values of those externally defined fields first, even if the original client query didn't request them.
type Product @key(fields: "id") {id: ID!size: Int @externalweight: Int @externalshippingEstimate: 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
.
ⓘ NOTE
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 |
---|---|
| Required. A GraphQL selection set (provided as a string) of Examples:
|
Applying metadata
@tag
Since 1.1
directive @tag(name: String!) repeatable on FIELD_DEFINITION | INTERFACE | OBJECT | UNION | ARGUMENT_DEFINITION | SCALAR | ENUM | ENUM_VALUE | INPUT_OBJECT | INPUT_FIELD_DEFINITION | SCHEMA
Applies arbitrary string metadata to a schema location. Custom tooling can use this metadata during any step of the schema delivery flow, including composition, static analysis, and documentation. The GraphOS Enterprise contracts feature uses @tag
with its inclusion and exclusion filters.
ⓘ NOTE
Unlike with most directives, composition preserves uses of this directive in the generated supergraph schema. To preserve uses of other directives, see @composeDirective
.
Consequently, if you rename this directive, you must use the same name in every subgraph that uses it. Otherwise, a composition error occurs due to a naming mismatch.
extend schema@link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@tag"])type Query {customer(id: String!): Customer @tag(name: "team-customers")employee(id: String!): Employee @tag(name: "team-admin")}interface User @tag(name: "team-accounts") {id: String!name: String!}type Customer implements User @tag(name: "team-customers") {id: String!name: String!}type Employee implements User @tag(name: "team-admin") {id: String!name: String!ssn: String!}
Arguments
Name / Type | Description |
---|---|
| Required. The tag name to apply. |
Managing custom directives
@composeDirective
Since 2.1
directive @composeDirective(name: String!) repeatable on SCHEMA
Indicates to composition that all uses of a particular custom type system directive in the subgraph schema should be preserved in the supergraph schema (by default, composition omits most directives from the supergraph schema).
⚠️ CAUTION
Do not use this directive with an executable directive. Executable directives have different rules for composition.
extend schema@link(url: "https://specs.apollo.dev/link/v1.0")@link(url: "https://specs.apollo.dev/federation/v2.3", import: ["@composeDirective"])@link(url: "https://myspecs.dev/myDirective/v1.0", import: ["@myDirective", { name: "@anotherDirective", as: "@hello" }])@composeDirective(name: "@myDirective")@composeDirective(name: "@hello")directive @myDirective(a: String!) on FIELD_DEFINITIONdirective @hello on FIELD_DEFINITION
This directive has the following requirements:
- Ensure your subgraph library supports
@composeDirective
or try manually adding the@composeDirective
definition to your subgraph schema. - 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 you use the
- 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 |
---|---|
| Required. The name (including the leading |
Saving and referencing data with contexts
@context
Since 2.8
This feature is only available with a GraphOS Enterprise plan.
You can test it out by signing up for a free Enterprise trial.
The @context
directive defines a named context from which a field of the annotated type can be passed to a receiver of the context. The receiver must be a field annotated with the @fromContext
directive.
directive @context(name: String!) on OBJECT | INTERFACE | UNION;
A @context
directive must be applied to an object, interface, or union type. A type can be annotated with one or more @context
directives.
Each @context
must be defined with a name, and each @context
name can be applied to multiple places within a subgraph. For example:
type A @key(fields: "id") @context(name: "userContext") {id: ID!prop: String!}type B @key(fields: "id") @context(name: "userContext") {id: ID!prop: String!}type U @key(fields: "id") {id: ID!field (arg: String @fromContext(field: "$userContext { prop }")): String!}
@fromContext
Since 2.8
This feature is only available with a GraphOS Enterprise plan.
You can test it out by signing up for a free Enterprise trial.
The @fromContext
directive sets the context from which to receive the value of the annotated field. The context must have been defined with the @context
directive.
scalar ContextFieldValue;directive @fromContext(field: ContextFieldValue) on ARGUMENT_DEFINITION;
A @fromContext
directive must be used as an argument on a field. Its field value—the ContextFieldValue
scalar—must contain the name of a defined context and a selection of a field from the context's type.
The selection syntax for @fromContext
used in its ContextFieldValue
is similar to GraphQL field selection syntax, with some additional rules:
- The first element must be the name of a context defined by
@context
and prefixed with$
(for example,$myContext
). This is the only context that can be referenced by the annotated field. - The
@skip
and@include
directives must not be used. - The second element must be a selection set that resolves to a single field.
- Top-level type conditions must not overlap with one another, so that the field can be resolved to a single value.
- All fields referenced in the
ContextFieldValue
must be expressed within the current subgraph. If the fields are referenced across multiple subgraphs, they must be annotated with@external
. - The argument must be nullable. Because validation is done at the subgraph level, the referenced field may become nullable when merging subgraphs, such as when the field is nullable in one subgraph but not in another.
When the same contextual value is set in multiple places, the ContextFieldValue
must resolve all types from each place into a single value that matches the parameter type.
For examples using @context
and @fromContext
, see Using contexts to share data along type hierarchies.