What is query complexity analysis and depth limiting in GraphQL?
Understand GraphQL depth limiting and query complexity analysis: how each bounds query cost, why you need both, and how to enforce them at validation time.
Expected Interview Answer
Depth limiting rejects any GraphQL query whose nesting exceeds a maximum number of levels, while query complexity analysis assigns each field a cost and rejects queries whose total computed cost exceeds a budget — both bound how expensive a query can be before it executes.
Depth limiting is a simple structural guard: it counts how deeply selection sets nest and blocks recursive or cyclic explosions like `friends { friends { friends ... } }`. Complexity analysis is more precise: each field gets a base cost, list fields multiply by their pagination argument (e.g. `first: 100`), and the summed score is checked against a maximum. Depth alone can miss wide, expensive-but-shallow queries, so production APIs typically combine both, running them as validation rules that reject offending operations before any resolver executes.
- Bounds query cost before execution starts
- Stops recursive/cyclic query explosions
- Catches wide, shallow queries that depth misses
- Runs at validation time, cheap to enforce
- Gives predictable, protectable server load
AI Mentor Explanation
Depth limiting is like capping the number of overs so an innings cannot run forever, while complexity analysis is like a total run-rate budget that also weighs how many fielders and reviews each over consumes. One bounds length, the other bounds effort, and together they keep any single innings from exhausting the day, just as both guards bound a query.
Step-by-Step Explanation
Step 1
Register validation rules
Add depth-limit and complexity rules to the server so they run during query validation, before resolvers.
Step 2
Set a depth maximum
Choose a sensible ceiling (e.g. 7) that fits legitimate use but blocks recursive nesting.
Step 3
Assign field costs
Give scalars a low cost and connection fields a cost multiplied by their `first`/`last` argument.
Step 4
Define a complexity budget
Pick a maximum total score; reject queries whose summed cost exceeds it with a clear error.
Step 5
Combine and monitor
Use both rules together, log computed scores, and tune limits from real traffic patterns.
What Interviewer Expects
- Correct definitions of both depth limiting and complexity analysis
- Why depth alone is insufficient for wide queries
- How pagination arguments factor into cost
- That both run at validation time before execution
- Awareness that they combat denial-of-service
Common Mistakes
- Treating depth limiting and complexity analysis as the same thing
- Ignoring pagination multipliers when scoring cost
- Setting limits so low that legitimate queries break
- Enforcing limits at runtime instead of validation time
- Using only depth limiting and missing wide, shallow attacks
Best Answer (HR Friendly)
“Depth limiting stops queries that are nested too deeply, like a list inside a list inside a list forever. Complexity analysis goes further by giving every part of a query a cost and blocking any request whose total cost is too high. Together they stop overly expensive queries from overloading the server.”
Code Example
import depthLimit from 'graphql-depth-limit'
import { createComplexityRule, simpleEstimator } from 'graphql-query-complexity'
import { ApolloServer } from '@apollo/server'
const server = new ApolloServer({
schema,
validationRules: [
depthLimit(7),
createComplexityRule({
maximumComplexity: 1000,
estimators: [simpleEstimator({ defaultComplexity: 1 })],
}),
],
})type Query {
# a shallow but wide query: cost = 100 * per-user field cost
users(first: Int = 20): [User!]! @complexity(multipliers: ["first"], value: 1)
}
# users(first: 100) { posts(first: 100) { title } }
# depth is only 3, but complexity is ~100 * 100 = 10000 -> rejectedFollow-up Questions
- Why can a shallow query still be extremely expensive?
- How do pagination arguments influence a query's cost score?
- Where in the request lifecycle do these rules run?
- How would you pick good limit values for your API?
- How do complexity limits interact with persisted queries?
MCQ Practice
1. What does depth limiting primarily prevent?
Depth limiting caps how many levels a query may nest, stopping recursive explosions.
2. Why combine complexity analysis with depth limiting?
A shallow query can still fan out hugely via pagination, which complexity scoring catches but depth does not.
3. When do these rules typically run?
Both are validation rules, so they reject offending queries before any resolver executes.
Flash Cards
Depth limiting? — Rejects queries whose selection-set nesting exceeds a configured maximum level.
Query complexity analysis? — Assigns each field a cost, sums them, and rejects queries over a budget before execution.
Why isn't depth enough? — A shallow query can still be huge via wide pagination; complexity scoring catches that.
How do lists affect cost? — Connection fields multiply their base cost by the pagination argument like `first`.
When do the rules run? — At validation time, before any resolver executes, so cost is bounded up front.
Continue Learning
Related Interview Questions
How do you secure a GraphQL API against malicious queries?
hard
What is the N+1 problem in GraphQL and how does DataLoader solve it?
hard
How does pagination work in GraphQL with cursor-based connections?
medium
What is the difference between over-fetching and under-fetching, and how does GraphQL address them?
medium