Skip to content

GraphQL Resolver Context — Sharing Authentication, Database, and State Across Resolvers

DodaTech Updated 2026-06-28 3 min read

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

  1. How is context created in Apollo Server?
  2. What is the third argument in a resolver function?
  3. Why should DataLoaders be created in context?
  4. How do you access context in resolvers?
  5. Can context be different for different subscriptions?

Answers:

  1. Via a context function passed to the Apollo Server constructor.
  2. The context object.
  3. DataLoaders must be per-request to batch queries within the same request.
  4. As the third argument: (parent, args, context, info).
  5. 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

Can context be asynchronous?

Yes. Context functions can be async, returning a promise that resolves to the context object.

Is context shared across all resolvers?

Yes. The same context object is passed to every resolver in the request.

How do I pass context to subscriptions?

Subscriptions have a separate context function that receives the WebSocket connection.

Can I have different context for different operations?

Yes. You can create different context functions for queries, mutations, and subscriptions.

Is context serialized?

No. Context is server-side only and is not serialized in the response.

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