GraphQL Resolver Context — Sharing Authentication, Database, and State Across Resolvers
In this tutorial, you will learn about GraphQL Resolver Context. We cover key concepts, practical examples, and best practices to help you master this topic.
GraphQL resolver context is an object shared across all resolvers in a single request, containing authentication data, database connections, DataLoader instances, and other request-scoped state.
What You'll Learn
- Creating and populating resolver context
- Using context for authentication
- Sharing DataLoader instances via context
Why It Matters
Context eliminates the need to pass authentication and database access through resolver arguments. It centralizes request-scoped state and enables cross-cutting concerns.
Code Examples
// Creating context with authentication
const server = new ApolloServer({
typeDefs,
resolvers,
context: async ({ req }) => {
// Extract token from headers
const token = req.headers.authorization?.replace('Bearer ', '');
// Verify token and get user
let user = null;
if (token) {
try {
user = await verifyToken(token);
} catch (e) {
// Token invalid, user remains null
}
}
// Create DataLoader instances per request
return {
user,
db: database,
loaders: {
user: new DataLoader(ids => batchLoadUsers(ids)),
post: new DataLoader(ids => batchLoadPosts(ids)),
comment: new DataLoader(ids => batchLoadComments(ids)),
},
// Helper methods
isAuthenticated: !!user,
isAdmin: user?.role === 'admin'
};
}
});
// Using context in resolvers
const resolvers = {
Query: {
me: (parent, args, context) => {
if (!context.isAuthenticated) {
throw new AuthenticationError('Not authenticated');
}
return context.user;
},
users: async (parent, args, context) => {
// Admin only
if (!context.isAdmin) {
throw new ForbiddenError('Admin access required');
}
return context.db.users.findAll();
}
},
User: {
posts: (parent, args, context) => {
return context.loaders.post.load(parent.id);
}
},
Mutation: {
createPost: async (parent, { input }, context) => {
if (!context.isAuthenticated) {
throw new AuthenticationError('Not authenticated');
}
return context.db.posts.create({
...input,
authorId: context.user.id
});
}
}
};
# Python context with Strawberry
import strawberry
from strawberry.types import Info
@strawberry.type
class Query:
@strawberry.field
async def me(self, info: Info) -> User | None:
user = info.context.get('user')
if not user:
raise Exception('Not authenticated')
return user
# Creating context
async def get_context(request):
token = request.headers.get('authorization', '').replace('Bearer ', '')
user = await verify_token(token) if token else None
return {
'user': user,
'db': database,
'is_admin': user and user.role == 'admin'
}
Common Mistakes
1. Putting Too Much in Context
Keep context minimal. Only include request-scoped data needed by resolvers.
2. Creating DataLoaders Outside Context
DataLoaders must be created per request to ensure proper batching and caching.
3. Mutating Context in Resolvers
Context should be read-only in resolvers. Mutate it only in the context creation function.
4. Not Handling Missing Authentication
Context should handle missing auth gracefully, setting user to null instead of throwing.
5. Sharing Heavy Objects in Context
Avoid putting large objects in context. Use Lazy Loading or references.
Practice Questions
- How is context created in Apollo Server?
- What is the third argument in a resolver function?
- Why should DataLoaders be created in context?
- How do you access context in resolvers?
- Can context be different for different subscriptions?
Answers:
- Via a context function passed to the Apollo Server constructor.
- The context object.
- DataLoaders must be per-request to batch queries within the same request.
- As the third argument: (parent, args, context, info).
- Yes. Subscriptions can have their own context function for Websocket authentication.
Challenge: Build a context system with authentication, role-based authorization, DataLoader instances, database connection, request ID for logging, and Rate Limiting counters.
FAQ
Mini Project
Build a comprehensive context system with authentication, DataLoader, database, logging, rate limiting, and feature flags. Demonstrate context usage across queries, mutations, and subscriptions with proper error handling.
What's Next
Learn about mutation return types for structured mutation responses, then explore subscription filtering for event filtering.
Built by the developers of DodaTech
Doda Browser, DodaZIP & Durga Antivirus Pro