100% Free Forever
AI-Powered Learning
Industry Expert Content
Certificates & Badges
Learn At Your Own Pace
GraphQL

The Resolver Chain and Context

Understand how resolvers link together into a chain across the query tree and how the shared context object flows through that chain.

ResolversIntermediate10 min readJul 10, 2026
Analogies

From a Flat Query to a Resolver Tree

A GraphQL query is nested text, but execution turns it into a tree of resolver calls that mirrors that nesting exactly. The root Query resolver runs first, and whatever it returns becomes the parent argument for each resolver on the fields selected beneath it, and so on down to the leaves. This chain means a resolver never needs to know how it was reached; it only needs to trust that its parent argument already contains what the resolver above produced.

🏏

Cricket analogy: A run chase unfolds over by over, each over's outcome shaped by the state left by the previous one, just as each resolver in the chain builds on the state left by the resolver above it.

What Lives in the Context Object

Unlike parent, which changes at every level of the tree, context is created exactly once per incoming request and passed unchanged to every resolver, no matter how deeply nested. Typical Apollo Server or graphql-js setups build context in a function tied to the server's request handler, populating it with the authenticated user (decoded from a JWT), a database client or ORM instance, request-scoped dataloaders, and sometimes feature flags. Because context is shared and mutable, some teams also use it to cache values computed once and reused by multiple resolvers within the same request.

🏏

Cricket analogy: The match umpire's decision review system data is available to every official on the field for that entire match, not recalculated per ball, just as context is built once and shared across every resolver in a request.

javascript
const server = new ApolloServer({ typeDefs, resolvers });

const { url } = await startStandaloneServer(server, {
  context: async ({ req }) => {
    const token = req.headers.authorization || '';
    const user = await getUserFromToken(token);
    return {
      user,
      db: dbClient,
      loaders: {
        bookById: createBookLoader(dbClient),
      },
    };
  },
});

// later, in a resolver:
// author: (parent, args, context) => context.loaders.bookById.load(parent.authorId)

Context Is Immutable Across the Tree, Not Across Requests

A common mistake is assuming context can be reused between requests to cache expensive work; it cannot safely be, because each incoming HTTP request gets a fresh context object, and reusing state across requests risks leaking one user's data (like their authenticated identity) into another user's response. The correct pattern for cross-request caching is a separate long-lived cache (Redis, an in-memory LRU) that context references, rather than storing per-user data directly on a module-level singleton.

🏏

Cricket analogy: A stadium's electronic scoreboard resets to zero at the start of every new match rather than carrying over the previous match's score, just as context resets fresh for every new request.

Never store user-specific data on a module-level variable or singleton outside the context function. Node.js servers handle many concurrent requests on one process, so shared mutable state outside context can leak one user's session into another's response.

Apollo Server also supports a contextValue function per request in newer API versions; the concept is identical, only the setup syntax has shifted across major versions of the library.

  • GraphQL execution turns a nested query into a tree of resolver calls matching its shape.
  • Each resolver receives the value its parent resolver returned via the parent argument.
  • context is built exactly once per request and passed unchanged to every resolver in the tree.
  • Typical context contents include the authenticated user, database clients, and dataloaders.
  • Context must never persist or leak state across separate HTTP requests.
  • Cross-request caching should use an external store like Redis referenced from context, not module-level singletons.
  • Resolvers should trust their parent argument rather than trying to know their position in the overall query.

Practice what you learned

Was this page helpful?

Topics covered

#GraphQL#GraphQLStudyNotes#WebDevelopment#TheResolverChainAndContext#Resolver#Chain#Context#Flat#APIs#StudyNotes#SkillVeris