In short
A GraphQL server has two halves. The schema is the menu of what clients can ask for. Resolvers are the cooks who fetch each item. Get both right and the API nearly documents itself.
The schema defines your API's types and operations; resolvers are the functions that actually fetch the data for each field — together they form a working GraphQL API.

Think of it like this
The wedding caterer's menu and cooks
The caterer gives guests a menu card: these dishes, nothing else. Behind the curtain, each cook owns one dish. A guest orders three, and only those three cooks get busy. The schema is the menu card. Each resolver is the cook for one field.
Watch it happen
Resolving book(id: 1) { title author { name } }
1/4The Query.book resolver runs first and loads book 1 from the database.
The big ideas
What you need to know
The schema is the contract
Written in SDL: types, fields and their types. Clients can only ask for what's declared.
A resolver per field
Each field can have a function (parent, args, context) that returns its value. Plain fields use a default.
Resolvers run as a tree
Parents resolve first and pass their result down. That's how nested data comes together.
Watch for N+1
Listing 50 books that each fetch their author means 51 queries. DataLoader batches them into two.
See it in code
Walk through the code
1import { ApolloServer } from "@apollo/server";2import { startStandaloneServer } from "@apollo/server/standalone";3 4const typeDefs = `#graphql5 type Author { id: ID!, name: String! }6 type Book { id: ID!, title: String!, author: Author! }7 type Query { book(id: ID!): Book }8`;9 10const resolvers = {11 Query: { book: (_: unknown, { id }: { id: string }) => db.books.find(id) },12 Book: { author: (book: { authorId: string }) => db.authors.find(book.authorId) },13};14 15const server = new ApolloServer({ typeDefs, resolvers });16await startStandaloneServer(server, { listen: { port: 4000 } });1/3The schema in SDL. The ! means non-null. Query.book is the only entry point.
db is your data layer. Open http://localhost:4000 to try queries in Apollo's built-in sandbox.
Save yourself the pain
Common mistakes
Oops
Writing a resolver for every single field, even plain ones.
Do this instead
Fields like title already resolve by reading parent.title. Only write resolvers for fields that need extra work.
Oops
Fetching each book's author with its own query in a list.
Do this instead
Use DataLoader to batch those lookups into one WHERE id IN (...) query per request.
Your mission
Add a reviews field
Quick check
In the resolver Book.author(book), what is the book argument?
Go deeper
- 1Define types, queries and mutations in a GraphQL schema.
- 2Write resolvers that fetch data from a database for each field.
- 3Learn the N+1 query problem in GraphQL and how DataLoader solves it.
More topics at this stop
Stuck on this topic? Ask an Insider
Get 1:1 guidance from people who've walked this exact path — on the InsideEdge app.