GraphQL Resolver Arguments and Context

Two of the four resolver arguments — args and context — are the ones you use most in real applications. args carries client-supplied data into the resolver. context carries server-supplied shared resources like the database connection and the authenticated user.

The args Argument

args is a plain JavaScript object. Each key corresponds to an argument the client passed in the query. If the client sends product(id: "42", currency: "INR"), then args inside the resolver is { id: "42", currency: "INR" }.

  Schema:
  ────────
  type Query {
    product(id: ID!, currency: String): Product
  }

  Resolver:
  ──────────
  const resolvers = {
    Query: {
      product: (parent, args, context) => {
        console.log(args);
        // { id: "42", currency: "INR" }

        return db.products.findById(args.id);
      }
    }
  };

  Client query:
  ──────────────
  {
    product(id: "42", currency: "INR") {
      name
      price
    }
  }

The context Argument

context is an object created once per request and passed to every resolver in that request. It holds shared resources that all resolvers might need — the database client, the authenticated user object, a logger, or a cache client. You build context in the server setup code.

  Server setup — building context:
  ──────────────────────────────────
  const server = new ApolloServer({ typeDefs, resolvers });

  await startStandaloneServer(server, {
    context: async ({ req }) => {
      const token = req.headers.authorization || '';
      const user  = await getUserFromToken(token);

      return {
        db:   databaseClient,    ← Available in every resolver
        user: user,              ← The authenticated user
        log:  logger,            ← Logging utility
      };
    }
  });

  Using context in resolvers:
  ─────────────────────────────
  const resolvers = {
    Query: {
      myOrders: (parent, args, context) => {
        if (!context.user) throw new Error('Not authenticated');

        return context.db.orders.findByUserId(context.user.id);
        //     ↑ db comes from context
        //                               ↑ user.id comes from context
      }
    }
  };

Context Is Created Fresh Per Request

A new context object is created for every incoming request. This means user identity, request headers, and other per-request data are isolated. Two simultaneous requests from different users never share context data.

  Request 1 (User A)             Request 2 (User B)
  ──────────────────             ──────────────────
  context = {                    context = {
    user: { id: "A", ... },        user: { id: "B", ... },
    db:   dbClient,                db:   dbClient,
  }                              }

  Resolvers for Request 1        Resolvers for Request 2
  see User A's context only      see User B's context only

Putting args and context Together

  Schema:
  ────────
  type Mutation {
    createComment(postId: ID!, text: String!): Comment!
  }

  Resolver:
  ──────────
  const resolvers = {
    Mutation: {
      createComment: async (parent, args, context) => {
        if (!context.user) {
          throw new Error('You must be logged in to comment');
        }

        const comment = await context.db.comments.create({
          postId:   args.postId,       ← From client query
          text:     args.text,         ← From client query
          authorId: context.user.id,   ← From server context
        });

        return comment;
      }
    }
  };

The info Argument

The fourth resolver argument, info, contains technical information about the current query execution — the field name, the full query AST, the return type, and the path to the current field. Most resolvers never use info. It becomes useful in advanced scenarios like building custom caching layers or query analyzers.

Key Points

  • args holds all arguments the client passed to the field in the query.
  • context holds shared server-side resources: the database, authenticated user, logger, and cache.
  • Context is built once per request and passed to every resolver in that request.
  • Two simultaneous requests never share context, keeping user data isolated.
  • info contains query metadata and is only needed in advanced use cases.

Leave a Comment