What the GraphQL Query Complexity Estimator does
This estimator parses a GraphQL operation with its fragments and works out how expensive it is to answer: query depth, the number of aliases, and a weighted cost in which every list multiplies the work beneath it. Each field's contribution is shown, so the total can be checked line by line rather than trusted.
GraphQL lets a client ask for a great deal in one request. Twenty aliased copies of a field, or three nested lists of 50, look small on screen and fan out into thousands of resolver calls. Servers defend with depth limits and cost limits; this page lets you see where a query stands against the limits you choose before it reaches one.
How to use it
- Paste the operation, including any fragments it spreads. If the document has several operations, name the one to cost under the advanced options.
- Paste the schema SDL too if you can. It tells the estimator which fields return lists and lets it report unknown fields, missing required arguments and misplaced selections.
- Set the weights and limits to match your server - or keep the defaults: 1 per object field, 0 per leaf, 10 items for a list with no size argument, and limits of cost 1,000, depth 10 and 15 aliases.
- Add variables as JSON when sizes come from variables, and per-field overrides such as
Query.search = 10for resolvers you know are expensive. - Choose Estimate cost, read the verdicts, then use the cost tree to find the field that dominates the total.
Reading the results
Subtree cost is a field's own weight plus its multiplier times everything selected under it, so the top-level rows add up to the total. The field with the largest subtree is where a limit or a smaller page size will have the most effect.
Multiplier comes from a size argument when there is one (first, last, limit and similar), from its variable or the variable's default, and otherwise from the assumed list size. A Relay connection passes its first to edges or nodes, so the size is not counted twice.
Fields inside inline fragments on a union or interface are all added, as if every branch were returned. That is an upper bound, which is what a cost limit should enforce.
Worked example: a bookshop listing page
The first example asks for books(first: $first) with $first defaulting to 20, each book's card fields through a BookCard fragment, its first 5 reviews with the reviewer's name, the page info, and an aliased search for 3 results with an inline fragment per result type.
Working up from the leaves with the default weights: a review is 1 (its author object) under a reviews field of weight 1 with multiplier 5, so reviews costs 1 + 5 x 1 = 6. A book node costs 1 + 1 (author) + 6 = 8. edges costs 1 + 20 x 8 = 161, books costs 1 + 161 + 1 (pageInfo) = 163, and search costs 1 + 3 x 1 = 4 because Author.books(first: 2) contributes 1. The total is 167, at depth 6 with 1 alias - within every default limit.
The second example repeats book(id) twenty times under aliases, each with 50 reviews whose authors list their own reviews. Each copy costs 1 + (1 + 50 x (1 + (1 + 10 x 0))) = 102, so the total is 2,040 with 20 aliases: it fails both the cost and alias limits while staying only 5 levels deep - exactly why depth limits alone are not enough.
Formulas and scoring rules
- Field cost
cost(field) = weight(field) + multiplier(field) x sum(cost(child) for each selected child)Leaves have no children, so their cost is their weight.- Weight
weight = override(Type.field) if set, else objectWeight (default 1) for fields with a selection set, else scalarWeight (default 0)- Multiplier
multiplier = size argument value (first, last, limit, pageSize, perPage, top, count, take, size) ; else defaultListSize (default 10) for list fields ; else 1A sized field that is not a list passes its size to its edges or nodes list instead.- Operation cost
total = sum(cost(root field)) over the operation's root selections, with fragments expanded in placeNo rounding; fractional weights are shown to two decimals.- Depth
depth = the largest number of nested fields on any path; fragments and inline fragments add no level
This cost model is a convention, not a standard
The GraphQL specification defines the language and execution, not what a query costs. The formula here is the widely used "weight plus multiplier times children" approach found in several server libraries and public APIs, with the defaults stated on the page. Your server may count differently - some charge per returned node, some add a base cost per request, some weigh mutations more - so set the weights to match it and treat the number as an estimate.
What the page does implement from the specification is parsing (section 2, Language) and a set of validation rules: fields must exist on their type, required arguments must be given, leaves take no selection set and objects need one, fragments must exist and not form cycles, and every variable used must be declared.
Limitations: what the result does not prove
- It estimates work from the query text. Real cost depends on resolvers, caching, batching (DataLoader) and data size, none of which a query can reveal.
- Without the schema, list fields are guessed from size arguments and plural names, so the estimate can be too low or too high; the hero line says when that happened.
- Custom directives such as
@costor@listSizein your SDL are not read. Put the same numbers in the per-field overrides. - The operation is only parsed. Nothing is sent to a GraphQL endpoint, so server-side limits and persisted-query rules are not checked.
Privacy: where your data goes
Everything you paste, type or drop is processed in this browser tab. It is not uploaded, logged, stored or sent to analytics. Session recording and tag-manager scripts are switched off on this page.
Standards and sources
- GraphQL specification (October 2021) - checked 19 Sep 2026
- GraphQL.org - Security: depth and complexity limits
- Relay Cursor Connections specification
- OWASP GraphQL Cheat Sheet
Frequently asked questions
What is a good maximum query cost for a public GraphQL API?
There is no universal number; it depends on your weights. Cost your heaviest legitimate screens with this page, set the limit comfortably above the largest of them, and log rejections so you can raise it deliberately. Public APIs typically pair a per-query limit with a per-client budget over time.
Why is a depth limit not enough to stop expensive GraphQL queries?
Because cost grows with breadth as well as depth. The alias example is only five levels deep but asks for twenty copies of the same expensive field. Aliases and large list sizes multiply work without adding depth, so limit cost and aliases too.
How does it treat Relay connections with edges and node?
When a field with a size argument such as first: 20 returns a connection object rather than a list, that size is applied to its edges or nodes list. The connection itself is counted once, so the page size is not multiplied twice.
Do fragments change the cost of a GraphQL query?
No. Named fragments and inline fragments are expanded into the fields they contain, which is how a server executes them. They cost exactly what the same fields would cost written out, and they add no depth.
What happens when a size argument is a variable without a value?
The variable's default is used if the operation declares one. Otherwise the assumed list size is used and the Why column says so. Supply the variables JSON to cost the query exactly as a client would send it.
Can I make some resolvers more expensive than others?
Yes. Add lines such as Query.search = 10 or Book.reviews = 3 under Per-field weights. The override replaces the default weight for that field wherever it appears, and still multiplies with any list above it.
Last reviewed by the A2Z.Tools team against the sources listed above.