GraphQL Directives – @include and @skip
Directives modify how the GraphQL server processes fields. The two built-in directives — @include and @skip — let you conditionally include or exclude fields in a query based on a variable. They eliminate the need to build different queries for different UI states.
What a Directive Looks Like
field @directiveName(argument: value)
Examples:
──────────
name @include(if: $showName)
price @skip(if: $hidePrice)
reviews @include(if: $showReviews) {
rating
comment
}
@include — Show a Field When Condition Is True
@include(if: Boolean) includes the field in the response when the condition is true. When the condition is false, the server skips the field entirely — it does not appear in the response at all.
Query:
───────
query GetProduct($id: ID!, $showReviews: Boolean!) {
product(id: $id) {
name
price
reviews @include(if: $showReviews) {
rating
comment
}
}
}
Variables: { "id": "p1", "showReviews": true }
Response includes reviews:
───────────────────────────
{
"product": {
"name": "Noise-Cancelling Headphones",
"price": 149.99,
"reviews": [
{ "rating": 5, "comment": "Excellent sound!" }
]
}
}
Variables: { "id": "p1", "showReviews": false }
Response has no reviews key at all:
─────────────────────────────────────
{
"product": {
"name": "Noise-Cancelling Headphones",
"price": 149.99
}
}
@skip — Hide a Field When Condition Is True
@skip(if: Boolean) is the reverse of @include. The field is skipped when the condition is true and included when it is false.
query GetUser($id: ID!, $isGuest: Boolean!) {
user(id: $id) {
name
email @skip(if: $isGuest) ← hide for guests
phone @skip(if: $isGuest) ← hide for guests
}
}
$isGuest: true → only name is returned
$isGuest: false → name, email, and phone are returned
@include vs @skip — Choosing One
Use @include when your variable name is positive:
showDetails, withReviews, includeAddress → @include(if: $var)
Use @skip when your variable name is negative:
isGuest, hidePrice, skipExtras → @skip(if: $var)
They are logical inverses:
@include(if: true) = @skip(if: false) = field appears
@include(if: false) = @skip(if: true) = field disappears
Using Directives on Fragments
Directives also work on fragment spreads. This lets you conditionally include an entire group of fields at once.
fragment AdminFields on User {
role
permissions
lastLoginAt
}
query GetUser($id: ID!, $isAdmin: Boolean!) {
user(id: $id) {
name
email
...AdminFields @include(if: $isAdmin)
}
}
Real-World Pattern — Feature Flags
Directives work well with feature flags. Your app checks a feature flag and passes the result as a variable. The query fetches extra data only when the feature is enabled — no extra code needed on the server.
const showBetaWidget = featureFlags.get('beta_widget');
const query = gql`
query Dashboard($showBeta: Boolean!) {
stats { visitors revenue }
betaMetrics @include(if: $showBeta) {
experimentGroup
conversionRate
}
}
`;
useQuery(query, { variables: { showBeta: showBetaWidget } });
Key Points
- Directives modify field behavior at query time without changing the schema.
@include(if: true)includes the field;@include(if: false)omits it entirely.@skip(if: true)omits the field;@skip(if: false)includes it.- Directives accept variables, making conditional field selection fully dynamic.
- Directives work on individual fields and on fragment spreads.
