A resolver is a function attached to a field in the GraphQL schema that knows how to fetch that field's value. When a query arrives, the GraphQL engine walks the requested fields and invokes their resolvers, which may read from a database, call another service, or compute a value. Resolvers receive arguments like the parent object, field arguments, and a shared context (e.g. the authenticated user). This per-field resolution is what lets clients request exactly the fields they want, but it also creates performance pitfalls like the N+1 problem.
2 / 5
What is the N+1 query problem in GraphQL, and how does a DataLoader solve it?
The N+1 problem arises when a query returns a list of N parent objects and each parent's child field resolver runs its own query — one query for the list plus N for the children. For 100 posts, that is 101 database round-trips. A DataLoader fixes this by batching: it collects all the individual child requests made during one tick of the event loop and issues a single batched query (e.g. WHERE id IN (...)), and it caches within the request to deduplicate. This turns N+1 into 2 queries and is essential for performant GraphQL.
3 / 5
In GraphQL schema design, what is the difference between a query and a mutation?
By convention and design, queries are read-only operations for fetching data, and the GraphQL engine may resolve their top-level fields in parallel since reads have no side effects. Mutations represent writes (create/update/delete) and their top-level fields are executed sequentially, one after another, so that ordered changes do not race. A well-designed mutation also returns the modified object (or a payload type) so the client can update its cache without a follow-up query. Keeping reads in queries and writes in mutations is a core schema-design discipline.
4 / 5
Why is GraphQL schema versioning typically handled by evolution (deprecation) rather than v1/v2 endpoints?
REST often versions via separate endpoints (/v1, /v2) because changing a response shape breaks clients. GraphQL avoids this: since each client explicitly selects the fields it wants, you can add new fields freely without affecting anyone, and retire old ones by marking them @deprecated (with a reason) while monitoring usage. When no client requests a deprecated field, you can safely remove it. This continuous evolution model means a single, always-current schema rather than a proliferation of versioned APIs.
5 / 5
What is over-fetching and under-fetching, and how does GraphQL address them?
In a fixed REST endpoint, over-fetching means the response includes fields the client does not need (wasted bandwidth), and under-fetching means one endpoint does not return enough, forcing multiple round-trips to assemble a view. GraphQL addresses both by letting the client declare exactly the fields and nested relationships it wants in a single query: no more, no less, in one request. This precision is GraphQL's headline benefit, though it shifts complexity to the server (resolvers, query cost analysis, and guarding against expensive deeply-nested queries).