Directives
Configure GraphQL types, fields, and arguments
Looking for Apollo Federation directives? See Federation-specific GraphQL directives.
A directive decorates part of a GraphQL schema or operation with additional configuration. Tools like Apollo Server (and Apollo Client) can read a GraphQL document's directives and perform custom logic as appropriate.
Directives are preceded by the @
character, like so:
type ExampleType {oldField: String @deprecated(reason: "Use `newField`.")newField: String}
This example shows the @deprecated
directive, which is a default directive (i.e., it's part of the GraphQL specification). It demonstrates the following about directives:
- Directives can take arguments of their own (
reason
in this case). - Directives appear after the declaration of what they decorate (the
oldField
field in this case)
Valid locations
Each directive can only appear in certain locations within a GraphQL schema or operation. These locations are listed in the directive's definition.
For example, here's the GraphQL spec's definition of the @deprecated
directive:
directive @deprecated(reason: String = "No longer supported") on FIELD_DEFINITION | ARGUMENT_DEFINITION | INPUT_FIELD_DEFINITION | ENUM_VALUE
This indicates that @deprecated
can decorate any of the four listed locations. Also note that its reason
argument is optional and provides a default value. Usage examples of each location are provided below:
# ARGUMENT_DEFINITION# Note: @deprecated arguments _must_ be optional.directive @withDeprecatedArgs(deprecatedArg: String @deprecated(reason: "Use `newArg`")newArg: String) on FIELDtype MyType {# ARGUMENT_DEFINITION (alternate example on a field's args)fieldWithDeprecatedArgs(name: String @deprecated): String# FIELD_DEFINITIONdeprecatedField: String @deprecated}enum MyEnum {# ENUM_VALUEOLD_VALUE @deprecated(reason: "Use `NEW_VALUE`.")NEW_VALUE}input SomeInputType {nonDeprecated: String# INPUT_FIELD_DEFINITIONdeprecated: String @deprecated}
If @deprecated
appears elsewhere in a GraphQL document, it produces an error.
If you create a custom directive, you need to define it (and its valid locations) in your schema. You don't need to define default directives like @deprecated
.
Schema directives vs. operation directives
Usually, a given directive appears exclusively in GraphQL schemas or exclusively in GraphQL operations (rarely both, although the spec allows this).
For example, among the default directives, @deprecated
is a schema-exclusive directive and @skip
and @include
are operation-exclusive directives.
The GraphQL spec lists all possible directive locations. Schema locations are listed under TypeSystemDirectiveLocation
, and operation locations are listed under ExecutableDirectiveLocation
.
Default directives
The GraphQL specification defines the following default directives:
Directive | Description |
---|---|
@deprecated(reason: String) | Marks the schema definition of a field or enum value as deprecated with an optional reason. |
@skip(if: Boolean!) | If true , the decorated field or fragment in an operation is not resolved by the GraphQL server. |
@include(if: Boolean!) | If false , the decorated field or fragment in an operation is not resolved by the GraphQL server. |
Custom directives
⚠️ Apollo Server does not provide built-in support for custom directives that transform a schema.
Your schema can define custom directives that can then decorate other parts of your schema:
# Definitiondirective @uppercase on FIELD_DEFINITIONtype Query {# Usagehello: String @uppercase}
If you want to define a custom schema directive to transform your executable schema's behavior before providing that schema to Apollo Server, we recommend using the @graphql-tools
library. See our example of using a custom directive to transform a schema.
In subgraphs
⚠️ Important considerations
Before you use directives in a federated graph, make sure to consider the following:
- Custom directives are not included in your graph's composed supergraph schema. The composition process strips all subgraph directives. Only a given subgraph is aware of its own directives.
- Because directives are specific to individual subgraphs, it's valid for different subgraphs to define the same directive with different logic. Composition does not detect or warn about such inconsistencies.
- If multiple subgraphs can resolve a particular field, each subgraph should almost always apply the exact same set of custom directives (with the exact same accompanying logic) to that field. Otherwise, the behavior of that field might vary depending on which subgraph resolves it.
As our example shows, in Apollo Server 3 and 4 you can define a transformer function for each of your subgraph schema's custom directives.
To apply transformer functions to your executable subgraph schema, you first generate the subgraph schema with buildSubgraphSchema
as usual:
let subgraphSchema = buildSubgraphSchema({ typeDefs, resolvers });
But instead of passing the result directly to the ApolloServer
constructor, you first apply all of your transformer functions to it:
// Transformer function for an @upper directivesubgraphSchema = upperDirectiveTransformer(subgraphSchema, 'upper');
After applying all transformer functions, you provide your final subgraph schema to the ApolloServer
constructor as usual:
const server = new ApolloServer({schema: subgraphSchema,// ...other options...});