GraphQL What Are Resolvers

A resolver is a function on the server that provides the value for a single field in your schema. Every field in a GraphQL schema has a resolver. When a client requests a field, GraphQL calls that field's resolver to get the data. Resolvers are where your schema connects to the real world — databases, REST APIs, files, and anything else.

One Field, One Resolver

  Schema field          Resolver function
  ────────────          ─────────────────
  Query.user       ──►  () => db.findUser()
  User.name        ──►  (user) => user.name
  User.posts       ──►  (user) => db.findPostsByUser(user.id)
  Post.title       ──►  (post) => post.title

The Resolver Waterfall

GraphQL executes resolvers in a top-down cascade. The root resolver runs first and returns a parent object. Then each child field's resolver receives that parent object and returns its own value.

  Query: { user(id:"1") { name  posts { title } } }

  Step 1: Query.user resolver runs
          → Returns user object { id:"1", name:"Sam", ... }

  Step 2: User.name resolver runs with parent = user object
          → Returns "Sam"

  Step 3: User.posts resolver runs with parent = user object
          → Returns [{ id:"p1", title:"Hello" }, ...]

  Step 4: Post.title resolver runs for each post
          → Returns "Hello" for post p1

Resolver Function Signature

Every resolver receives four arguments, always in this order:

  function fieldResolver(parent, args, context, info) {
    // parent  → The object returned by the parent resolver
    // args    → Arguments passed by the client in the query
    // context → Shared data: database, auth token, logger
    // info    → Technical details about the query (rarely used)
  }

A Concrete Example

  Schema:
  ────────
  type Query {
    book(id: ID!): Book
  }

  type Book {
    id:     ID!
    title:  String!
    author: String!
  }

  Resolvers:
  ───────────
  const books = [
    { id: "1", title: "Dune",       author: "Frank Herbert" },
    { id: "2", title: "Foundation", author: "Isaac Asimov"  },
  ];

  const resolvers = {
    Query: {
      book: (parent, args, context) => {
        return books.find(b => b.id === args.id);
        //                     ↑ args.id comes from book(id: "1")
      }
    },
    Book: {
      title:  (parent) => parent.title,   ← parent is the book object
      author: (parent) => parent.author,
    }
  };

Default Resolvers Save You Work

GraphQL provides a built-in default resolver for any field you do not define yourself. The default resolver reads the property with the same name from the parent object. This is why the Book.title and Book.author resolvers in the example above are optional — GraphQL would handle them automatically.

  Default resolver behavior:
  ───────────────────────────
  Field: title
  Default resolver: (parent) => parent["title"]

  As long as the parent object has a "title" property,
  you do not need to write a resolver for it.

When You Must Write a Custom Resolver

  Situation                              Example
  ─────────                              ───────
  Field name differs from DB column      schema: fullName, DB: full_name
  Field needs a DB query                 user.posts → SELECT * FROM posts WHERE user_id=?
  Field combines multiple data sources   user.weather → city + weather API call
  Field transforms data                  price in cents → price in dollars
  Field applies business logic           user.isAdmin → check roles table

Key Points

  • Every schema field has a resolver function that provides its value.
  • Resolvers receive four arguments: parent, args, context, and info.
  • Resolvers run in a top-down cascade — the parent resolver's return value becomes the parent argument of child resolvers.
  • GraphQL provides default resolvers that read same-name properties from the parent object automatically.
  • Write custom resolvers when data needs a database query, transformation, or combination of sources.

Leave a Comment