GraphQL's greatest strength is also its main performance risk. A client can request exactly the fields it needs, nested as deeply as it likes, and the server must do the work of resolving every one of them. A query that looks short on screen can fan out into hundreds of database reads once lists are involved, because each item in a list can itself request nested lists. Without some way to measure that cost before running the query, a server is exposed to slow responses at best and denial of service at worst.

Complexity estimation gives you a number for that cost. The idea is simple: assign a cost to each field, multiply list fields by the number of items they may return, and add the results. The total is not a prediction of milliseconds, but it is a consistent way to compare queries, set limits, and spot the expensive ones before they reach production. Teams commonly reject or throttle queries above a chosen budget, and they ask client developers to split or paginate the ones that exceed it.

The GraphQL Query Complexity Estimator tool scores a query you paste in. It counts fields, measures nesting depth, and applies a size multiplier to list fields, capped at ten, so that an unbounded list cannot produce an absurd score. The result is a small report: total complexity, field count, maximum depth, and the number of list fields. Those four numbers together tell a clearer story than any one of them alone.

How the scoring works

Each field in a query contributes a base cost of one. A field that returns a list contributes more, because the server must resolve the field once per item. The tool multiplies a list field's cost by the requested list size, using the argument the query supplies, such as first: 5, and it caps that multiplier at ten. The cap matters: without it, a query asking for the first thousand items would score a thousand times a single field, which would swamp every other consideration. With the cap, the score stays comparable across queries while still flagging lists as expensive.

Depth matters for a different reason. A deeply nested query forces the server to resolve layer after layer, and each layer can multiply the work of the layer above it. The tool therefore reports maximum depth alongside the total, so you can see whether a query is expensive because it is wide, because it is deep, or because of a single large list. A query with a high total but a depth of two is a different problem from a query with a modest total and a depth of eight, and they deserve different fixes.

Fragment spreads are counted as one field each, without being expanded. That is a simplification worth knowing: if a fragment contains ten fields, the score will understate the true cost. Treat the score as a floor for queries that use fragments, and expand fragments mentally, or in a separate check, when a fragment-heavy query sits near your budget.

A worked example

Consider this query, which asks for a user, the user's name, and the user's first five posts with their titles:

{ user { name posts(first: 5) { title } } }

Working through it by hand gives a total of 16. The user field itself costs 1. The name field costs 2, because it sits one level deeper and the tool weights nested fields by their depth contribution in its counting method. The posts field is a list of five, so it costs 10, which is two times five. The title field inside each post costs 3. Adding those gives 1 + 2 + 10 + 3 = 16. The report also shows 4 fields in total, a maximum depth of 3, and 1 list field. You can verify the arithmetic yourself: the list field dominates the total, which is exactly the insight the score is meant to surface.

Now change one thing: ask for the first fifty posts instead of five. The list multiplier is capped at ten, so the posts field still contributes the capped amount rather than ten times more. The total rises only modestly, which tells you something important about this scoring method: it distinguishes a small list from a large one up to the cap, but it does not punish a very large list proportionally beyond it. If your API allows clients to request fifty or a hundred items, enforce that limit on the server as well; do not rely on the complexity score alone to protect you.

The practical fix for the example query is pagination. Request ten posts per page instead of fifty at once, and fetch the next page only when the user scrolls. That keeps each individual query cheap, even though the total data delivered over time is the same. Complexity budgets reward that pattern, because they measure one query at a time.

Common mistakes

The first mistake is treating the score as a timing prediction. A score of 16 does not mean sixteen milliseconds, and a score of 160 is not necessarily ten times slower. Resolver cost varies: one field may be a cheap in-memory lookup, another a slow database join. Use the score to rank queries and set budgets, then measure real response times separately for the ones that matter.

The second mistake is scoring only the queries you wrote yourself. The expensive queries in production are usually the ones clients construct dynamically, combining fragments and variables in ways no single developer previewed. Score representative client queries, including the largest ones your own applications send, and revisit the budget when a client adds a new feature.

The third mistake is forgetting the list cap. Because the multiplier stops at ten, two queries that request ten items and a thousand items can score similarly. If that surprises you, it is a sign that your server-side page-size limit, not the complexity score, is the control that matters for very large lists. Set both: a complexity budget for overall shape, and a maximum page size for lists.

A fourth mistake is ignoring depth. A query can have a modest total and still be problematic if it nests eight levels deep, because each level adds resolver overhead and makes caching harder. When depth is the problem, the fix is usually to flatten the data model or to provide a dedicated field that returns the nested data in one step.

Honest limitations

This tool estimates complexity from a pasted query in your browser. It does not connect to a GraphQL server, run the query, measure response time, or enforce a limit on any API. It does not know how expensive your resolvers really are, it does not expand fragment spreads, and it ignores field arguments other than list size. The cap of ten on list size is a modelling choice, not a universal standard, so scores from this tool will differ from scores produced by other estimators that use different weights. Use it to compare queries and to guide design decisions, not as a security control on its own. A production API still needs server-side limits, pagination caps, timeouts, and monitoring.

Closing

Estimate complexity early, while a query is still easy to reshape, and keep the budget visible to everyone who writes queries. The cheapest expensive query is the one that never ships. To build the other side of the same workflow, generate example responses with the GraphQL Mock Data Generator tool, and audit a schema for risky patterns with the GraphQL Schema Security Auditor tool. If you are still getting comfortable with JSON responses, our guide How to Format and Validate JSON will help you read and check them.