← Recipes

阅读中文版本

Limit GraphQL Query Complexity

Compute a cost for each query from field weights and list multipliers, reject queries above a budget, and return a clear error before execution.

~40 mingraphqlsecurityapi-design

Task

Protect a GraphQL server from deeply nested or wide queries that would exhaust the database.

When to use this

A single malicious or careless query with deep nesting and large list multipliers ties up the server, and depth limiting alone does not catch wide fan-out.

Prerequisites

  • A GraphQL server with validation hooks
  • A cost model per field

Steps

1. Assign a cost to scalar fields and multipliers to list fields.

Expected output: Each field contributes predictable cost.

2. Compute total complexity before execution and reject over budget.

Expected output: Expensive queries never reach resolvers.

3. Return a structured error naming the limit and the computed cost.

curl -X POST https://api.example.com/graphql -d '{"query":"{ user { posts { comments { author } } } }"}'

Expected output: Clients can fix their query.

4. Consider pagination everywhere so lists have bounded multipliers.

Expected output: The cost model has finite worst cases.

Troubleshooting

Problem

Legitimate queries rejected

Solution

Tune weights from real query profiles and allow a higher budget for authenticated clients.

Problem

Complexity ignores runtime cost

Solution

Combine static complexity with a per-resolver timeout so a cheap-looking but slow resolver is still bounded.

Limitations

  • Static complexity is an approximation and can both over- and under-estimate real cost.
  • It must be tuned against production traffic or it will either block valid queries or miss abuse.

Context

Protect a GraphQL server from deeply nested or wide queries that would exhaust the database. A single malicious or careless query with deep nesting and large list multipliers ties up the server, and depth limiting alone does not catch wide fan-out.

Steps

  1. Assign a cost to scalar fields and multipliers to list fields. Expected: Each field contributes predictable cost.
  2. Compute total complexity before execution and reject over budget. Expected: Expensive queries never reach resolvers.
  3. Return a structured error naming the limit and the computed cost. Expected: Clients can fix their query.
  4. Consider pagination everywhere so lists have bounded multipliers. Expected: The cost model has finite worst cases.
const cost = calculateComplexity(query, fieldWeights);
if (cost > BUDGET) {
  throw new GraphQLError(`Query too complex: ${cost} > ${BUDGET}`);
}

Verify

  • Each field contributes predictable cost.
  • Expensive queries never reach resolvers.
  • Clients can fix their query.
  • The cost model has finite worst cases.

Limits

  • Static complexity is an approximation and can both over- and under-estimate real cost.
  • It must be tuned against production traffic or it will either block valid queries or miss abuse.