Here's your chance to speak at GraphQL Summit in New York City, October 8 - 10, 2024! 🏙️ Submit your proposal by May 31.
Launch GraphOS Studio


Configure GraphQL types, fields, and arguments

Looking for ? See Federation-specific GraphQL directives.

A directive decorates part of a or with additional configuration. Tools like (and Apollo Client) can read a 's directives and perform custom logic as appropriate.

are preceded by the @ character, like so:

type ExampleType {
oldField: String @deprecated(reason: "Use `newField`.")
newField: String

This example shows the @deprecated , which is a default directive (i.e., it's part of the GraphQL specification). It demonstrates the following about directives:

  • Directives can take of their own (reason in this case).
  • Directives appear after the declaration of what they decorate (the oldField 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"

This indicates that @deprecated can decorate any of the four listed locations. Also note that its reason is optional and provides a default value. Usage examples of each location are provided below:

# Note: @deprecated arguments _must_ be optional.
directive @withDeprecatedArgs(
deprecatedArg: String @deprecated(reason: "Use `newArg`")
newArg: String
) on FIELD
type MyType {
# ARGUMENT_DEFINITION (alternate example on a field's args)
fieldWithDeprecatedArgs(name: String @deprecated): String
deprecatedField: String @deprecated
enum MyEnum {
OLD_VALUE @deprecated(reason: "Use `NEW_VALUE`.")
input SomeInputType {
nonDeprecated: String
deprecated: 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 or exclusively in GraphQL (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:

@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:

# Definition
directive @uppercase on FIELD_DEFINITION
type Query {
# Usage
hello: 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

Before you use custom directives in a federated , make sure to consider the following:

  • If multiple can resolve a particular field, each subgraph should almost always apply the exact same set of custom directives (with the exact same definition) to that field. Otherwise, the behavior of that field might vary depending on which resolves it.
  • Because directives are specific to individual subgraphs, it's technically valid for different subgraphs to define the same directive with different logic. As stated in the previous point, if a custom directive is used in multiple subgraphs to resolve a particular field, you should define the same directive with the same logic across subgraphs. Composition does not detect or warn about such inconsistencies.
  • The process treats executable (client-side) and type system (server-side) directives differently:
    • An executable directive is composed into the if:
      • All subgraphs define the directive identically
      • The directive is not included in any @composeDirective directives
    • directives are not composed into the supergraph schema, but they can provide information to the via the @composeDirective directive.

Transformer functions

As our example shows, in Apollo Server 3 and 4 you can define a transformer function for each of your '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 directive
subgraphSchema = 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...
Custom scalars
Edit on GitHubEditForumsDiscord

© 2024 Apollo Graph Inc.

Privacy Policy