Custom Directives
Create reusable GraphQL directives for authentication, caching, validation, and more.
What are Directives?
Directives add behavior to schema fields without changing resolvers:
graphql
type Query {
profile: User @auth
adminData: String @auth(requires: "ADMIN")
expensiveData: String @cache(ttl: 300)
}Creating a Directive
Basic Example
ts
// server/graphql/directives/auth.directive.ts
export const authDirective = defineDirective({
name: 'auth',
locations: ['FIELD_DEFINITION'],
description: 'Requires authentication',
transformer: (schema) => {
// Transform schema to add auth logic
return mapSchema(schema, {
[MapperKind.OBJECT_FIELD]: (fieldConfig) => {
const directive = getDirective(schema, fieldConfig, 'auth')?.[0]
if (directive) {
const { resolve = defaultFieldResolver } = fieldConfig
fieldConfig.resolve = async (source, args, context, info) => {
if (!context.auth) {
throw new GraphQLError('Unauthorized')
}
return resolve(source, args, context, info)
}
}
return fieldConfig
},
})
},
})With Arguments
ts
export const cacheDirective = defineDirective({
name: 'cache',
locations: ['FIELD_DEFINITION'],
args: {
ttl: { type: 'Int!', defaultValue: 60 },
scope: { type: 'String', defaultValue: 'PUBLIC' },
},
transformer: (schema) => {
// Implement caching logic
return schema
},
})Real-World Examples
See the playgrounds/nitro/server/graphql/directives/ directory for complete examples:
auth.directive.ts- Authenticationpermission.directive.ts- Role-based accesscache.directive.ts- Field-level cachingrate-limit.directive.ts- Rate limitingvalidate.directive.ts- Input validation