Skip to content
Blog

GraphQL rate limiting: prevent expensive automated queries

Bound GraphQL query depth, breadth, pagination, and cost. Learn why HTTP request limits alone miss expensive operations and how to review legitimate client impact.

Frederick Jahn
Frederick JahnSeptember 5, 2026
GraphQL rate limiting: prevent expensive automated queries

GraphQL rate limiting should account for the work inside an operation, not only the number of HTTP requests. One request can select many fields, traverse relationships, or ask for large lists.

Start with server-enforced bounds on returned data and operation shape. Then add client budgets that reflect estimated cost and actual service capacity. A bot assessment can inform policy, but it cannot calculate resolver cost or enforce object permissions on its own.

GraphQL's security guidance covers pagination, depth and breadth limits, and query complexity analysis. These controls address different forms of demand; none is a universal substitute for the others.

Review what a client can ask for

For each important operation, record its list sizes, relationship traversal, and expensive resolver dependencies. Include operations used by older application versions and approved integrations.

Do not assume that a shallow query is cheap. A broad selection can request many independent fields. A single expensive resolver can also dominate work even when depth is low.

Likewise, a persisted operation is not automatically safe merely because its text is stored. Review which documents are actually approved and whether client-supplied variables can expand their work beyond intended bounds.

Match each limit to its failure mode

ControlWhat it boundsWhat still needs review
Page-size capItems returned from a listNumber of lists selected
Depth limitNested relationship traversalBroad shallow operations
Breadth or alias limitRepeated parallel selectionsCost of each selection
Complexity allowanceEstimated operation workWhether estimates match resolver behavior
Concurrency limitOperations running togetherCost and duration of each operation
TimeoutAllowed execution durationWhether downstream work actually stops

Treat the table as a design worksheet. The correct combination depends on the implementation and the operations your clients need.

Keep authorization at the resource boundary. OWASP's REST guidance describes endpoint access control; for GraphQL, apply the same separation of traffic policy and access permission to the operations and resources being resolved.

Make cost estimates explainable

If you assign weights to fields, document the reason: database work, result size, or a constrained dependency. Avoid a scoring system that cannot explain why a normal operation is refused.

Compare estimated cost with observed execution time and downstream calls in a controlled environment. A schema change can make an old estimate inaccurate. Include cost review when a resolver gains a new dependency or a list changes its behavior.

Decide how variables affect cost before execution. If the calculation ignores a client-selected list size, the nominal budget may not bound the work you intended.

Review batching and retries explicitly

If the server accepts multiple operations in one HTTP request, establish whether each operation consumes an allowance. Check whether concurrent requests share the same account or tenant budget.

A retry after a timeout may arrive while earlier work is still running. Trace cancellation and duplicate mutation handling instead of assuming that the failed client request means the server did nothing.

Return an error the client understands. An HTML challenge in a GraphQL response path needs an explicit integration design; it should not appear unexpectedly inside a client expecting a structured response.

Test the approved client contract

Review a normal application screen, a mobile client, and any permitted reporting integration. Include maximum supported pagination and a rejected operation. Use synthetic data and bounded requests in an authorized environment; generating an uncontrolled load spike is unnecessary for this review.

After a change, monitor rejected operations by reason, successful completion, and backend saturation. Keep a route back to the previous configuration if approved clients break.

Use API rate-limit design for broader counting scopes and the API abuse use case for the product discussion. Bring a representative operation and its resource costs so the evaluation addresses the GraphQL workload, not just the HTTP endpoint.