Aliases and Directives: @include, @skip and @deprecated

Beginner
10 min

Aliases and Directives: @include, @skip and @deprecated

Two small features of the query language solve problems you will hit in your first real project: needing the same field twice with different arguments, and leaving out parts of a query without writing a second one. After this lesson you will be able to rename fields in a response, toggle fields with variables, and mark old schema fields as deprecated without breaking existing clients.

Aliases: Renaming Fields in the Response

A GraphQL response mirrors the shape of the query: every selected field becomes a key with the same name. That creates a conflict the moment you ask for the same field twice:

graphql
query { user(id: "1") { name } user(id: "2") { name } }

Validation rejects this because both selections would be written to the key user. An alias gives each selection its own key. Write the alias, a colon, then the field:

graphql
query { admin: user(id: "1") { name } editor: user(id: "2") { name } }

The response contains the alias names instead of the field names:

json
{ "data": { "admin": { "name": "Ada Lovelace" }, "editor": { "name": "Grace Hopper" } } }

Aliases work at any depth. Typical uses are fetching one field with different arguments (small: avatar(size: 64), large: avatar(size: 512)) and renaming fields to what your UI expects (fullName: name). The server resolves user exactly as before; only the response key changes.

What Directives Are

A directive is an annotation starting with @ that changes how part of a document or schema is handled. Servers may add custom directives, but the built-in ones below work everywhere.

| Directive | Used on | Purpose | |---|---|---| | @include(if: Boolean!) | Fields, fragment spreads, inline fragments | Include the selection only when if is true | | @skip(if: Boolean!) | Fields, fragment spreads, inline fragments | Omit the selection when if is true | | @deprecated(reason: String) | Field definitions, enum values, arguments, input fields | Mark schema members for removal |

Conditional Fields with @include and @skip

Both directives take a single if argument of type Boolean. The value almost always comes from a variable, so one query can serve several screens:

graphql
query Profile($withPosts: Boolean!, $hideEmail: Boolean = false) { me { name email @skip(if: $hideEmail) posts(limit: 3) @include(if: $withPosts) { title } } }

With variables { "withPosts": false, "hideEmail": true } the response is { "data": { "me": { "name": "Ada Lovelace" } } }. Skipped fields are absent from the result entirely, not set to null, so client code must treat the key as optional. Attaching a directive to a fragment spread toggles a whole block at once: ...OrderDetails @include(if: $detailed). If both directives appear on one field, it is included only when @include is true and @skip is false.

Deprecating Schema Fields

GraphQL APIs evolve in place instead of being versioned. When a field must be replaced, the old one stays in the schema and is marked with @deprecated so tools can warn developers:

graphql
type User { id: ID! name: String! fullName: String! @deprecated(reason: "Use `name` instead.") role: Role! } enum Role { ADMIN EDITOR MODERATOR @deprecated(reason: "Moderators were merged into EDITOR.") }

The reason argument is optional but should name the replacement. GraphiQL, Apollo Sandbox and code generators read this metadata through introspection and show a warning. Since graphql-js 16, arguments and input fields can be deprecated as well. Nothing changes at runtime: deprecated fields keep resolving until usage metrics show you can remove them.

Tips

  • Prefer @include with a positive variable name ($withPosts) over @skip with a negative one; double negatives are hard to read.
  • Never use directives as authorization. The client decides what is included, so sensitive data must be protected in resolvers.
  • Deprecate before you delete, and write the reason as a full sentence.
Quick Quiz
Question 1 of 2

Why does the query `{ user(id: "1") { name } user(id: "2") { name } }` fail validation?

Key Takeaways

  • An alias (alias: field) renames the response key and lets you request one field several times with different arguments.
  • @include(if:) and @skip(if:) conditionally include selections and are usually driven by Boolean variables.
  • Directives can be placed on fields, fragment spreads and inline fragments, so whole blocks can be toggled.
  • Skipped fields are absent from the response rather than null.
  • @deprecated(reason:) marks schema members for removal without breaking clients; deprecate first, remove later.

Next lesson: Fragments and Reusable Query Parts — extract repeated selection sets into named fragments and reuse them across queries.

Aliases and Directives: @include, @skip and @deprecated - GraphQL | CodeYourCraft | CodeYourCraft