GraphQL in Production · Performance and Caching
Protecting the Server: Depth, Complexity and Timeouts
Stop expensive or malicious queries before they run.
A single GraphQL document can request enormous work: deep nesting (friends { friends { friends … } }), huge page sizes, hundreds of aliases. Protect the server with max depth, query cost/complexity analysis (assign costs to fields, multiply by list sizes, reject over budget), pagination limits on every list, alias and token limits, execution timeouts, and rate limiting by cost rather than request count (as GitHub and Shopify do). For first-party apps, trusted documents (an allowlist of persisted operations) remove the problem entirely.
Defense layers
| Control | Stops | Notes |
|---|---|---|
| Max depth | Deeply nested recursion | Cheap; first line of defense |
| Cost/complexity analysis | Wide or multiplied lists | Needs field costs + list size args |
| Required pagination args | Unbounded lists | e.g. first ≤ 100 |
| Alias/token limits | Alias amplification | Batching tricks |
| Timeouts | Slow resolvers | Per request and per downstream call |
| Trusted documents | Arbitrary queries | Best for first-party clients |
import depthLimit from "graphql-depth-limit";
import { createComplexityLimitRule } from "graphql-validation-complexity";
const server = new ApolloServer({
schema,
validationRules: [
depthLimit(8),
createComplexityLimitRule(1000, { scalarCost: 1, objectCost: 2, listFactor: 10 }),
],
});
from strawberry.extensions import MaxAliasesLimiter, MaxTokensLimiter, QueryDepthLimiter
schema = strawberry.Schema(
query=Query,
mutation=Mutation,
extensions=[QueryDepthLimiter(max_depth=8), MaxAliasesLimiter(max_alias_count=15), MaxTokensLimiter(max_token_count=2000)],
)
# application.yml — plus a custom Instrumentation for cost analysis
spring:
graphql:
schema:
introspection:
enabled: false # in production for public APIs
# graphql-java: MaxQueryDepthInstrumentation(8), MaxQueryComplexityInstrumentation(1000)
Common pitfalls
- Rate limiting by request count when one request can cost 1000×.
- Lists without maximum page sizes.
- Leaving introspection and arbitrary queries open for first-party-only APIs.
Key points
- Depth + cost limits + pagination caps
- Rate limit by cost
- Trusted documents for first-party apps
Further reading: GitHub GraphQL: rate and node limits
Practice questions
Why do GitHub and Shopify rate-limit GraphQL by cost instead of request count?
Answer
One GraphQL request can trigger vastly different amounts of work; cost-based budgets reflect the actual load each query puts on the system.
What is an alias amplification attack?
Answer
Repeating an expensive field many times under different aliases in one query (or many mutations like login attempts) to multiply work or bypass per-request rate limits.
Open in the app to mark lessons complete, take notes and track your progress.