Skip to content

feat: support subgraph-level demand control#8829

Merged
carodewig merged 48 commits intodevfrom
caroline/demand-control-by-subgraph
Feb 9, 2026
Merged

feat: support subgraph-level demand control#8829
carodewig merged 48 commits intodevfrom
caroline/demand-control-by-subgraph

Conversation

@carodewig
Copy link
Contributor

@carodewig carodewig commented Jan 23, 2026

Note that this PR is based on #8827; it will need to be rebased once that PR is merged to dev.

Subgraph-level demand control lets you enforce per-subgraph query cost limits in Apollo Router, in addition to the existing global cost limit for the whole supergraph. This helps you protect specific backend services that have different capacity or cost profiles from being overwhelmed by expensive operations.

When a subgraph‑specific cost limit is exceeded, the router:

  • Still runs the rest of the operation, including other subgraphs whose cost is within limits.
  • Skips calls to only the over‑budget subgraph, and composes the response as if that subgraph had returned null, instead of rejecting the entire query.

Per‑subgraph limits apply to the total work for that subgraph in a single operation. For each request, the router tracks the aggregate estimated cost per subgraph across the entire query plan. If the same subgraph is fetched multiple times (for example, through entity lookups, nested fetches, or conditional branches), those costs are summed together and the subgraph’s limit is enforced against that total.

Configuration

demand_control:
  enabled: true
  mode: enforce
  strategy:
    static_estimated:
      max: 10
      list_size: 10
      actual_cost_mode: by_subgraph
      subgraphs: # <---- everything from here down is new (all fields optional)
        all:
          max: 8
          list_size: 10
        subgraphs:
          products:
            max: 6
            # list_size omitted, 10 implied because of all.list_size
          reviews:
            list_size: 50
            # max omitted, 8 implied because of all.max

Example

Consider a topProducts query, which fetches a list of products from a products subgraph and then performs an entity lookup for each product in a reviews subgraph. Assume that the products cost is 10 and the reviews cost is 5, leading to a total estimated cost of 15 (10 + 5).

Previously, you would only be able to restrict that query via demand_control.static_estimated.max:

  • If you set it <= 15, the query would execute
  • If you set it >15, the query would be rejected

This feature allows much more granular control. In addition to demand_control.static_estimated.max, which operates as before, there are also per subgraph maxes.

For example, if you set max = 20 and reviews.max = 2, the query will 'pass' the aggregate check (15 < 20) and will execute on the products subgraph (no limit specified), but will not execute against the reviews subgraph (5 > 2). The result will be composed as if the reviews subgraph had returned null.


Checklist

Complete the checklist (and note appropriate exceptions) before the PR is marked ready-for-review.

  • PR description explains the motivation for the change and relevant context for reviewing
  • PR description links appropriate GitHub/Jira tickets (creating when necessary)
  • Changeset is included for user-facing changes
  • Changes are compatible1
  • Documentation2 completed
  • Performance impact assessed and acceptable
  • Metrics and logs are added3 and documented
  • Tests added and passing4
    • Unit tests
    • Integration tests
    • Manual tests, as necessary

Exceptions

Note any exceptions here

Notes

Footnotes

  1. It may be appropriate to bring upcoming changes to the attention of other (impacted) groups. Please endeavour to do this before seeking PR approval. The mechanism for doing this will vary considerably, so use your judgement as to how and when to do this.

  2. Configuration is an important part of many changes. Where applicable please try to document configuration examples.

  3. A lot of (if not most) features benefit from built-in observability and debug-level logs. Please read this guidance on metrics best-practices.

  4. Tick whichever testing boxes are applicable. If you are adding Manual Tests, please document the manual testing (extensively) in the Exceptions.

@apollo-librarian
Copy link

apollo-librarian bot commented Jan 23, 2026

✅ Docs preview ready

The preview is ready to be viewed. View the preview

File Changes

0 new, 4 changed, 0 removed
* graphos/routing/(latest)/errors.mdx
* graphos/routing/(latest)/customization/coprocessor/reference.mdx
* graphos/routing/(latest)/customization/rhai/reference.mdx
* graphos/routing/(latest)/security/demand-control.mdx

Build ID: 00c93328b6d72fccc794ac9d
Build Logs: View logs

URL: https://www.apollographql.com/docs/deploy-preview/00c93328b6d72fccc794ac9d

@carodewig carodewig marked this pull request as ready for review January 26, 2026 15:13
@carodewig carodewig requested a review from a team January 26, 2026 15:13
@carodewig carodewig requested a review from a team as a code owner January 26, 2026 15:13
Copy link
Contributor

@aaronArinder aaronArinder left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

lgtm! consider merging in #8840 before merging this if you think that test is valuable (helped me understand that we're only doing accumulation into a sum, not any weird math, but wanted to put something in place to guard against the safety mechanisms being refactored into something dangerous)

@carodewig carodewig force-pushed the caroline/demand-control-by-subgraph branch from a2526bd to aee2352 Compare January 29, 2026 16:51
carodewig and others added 2 commits January 29, 2026 11:54
Co-authored-by: Aaron <aaronarinder@gmail.com>
@carodewig
Copy link
Contributor Author

@aaronArinder that test is a great idea! I've cherrypicked it in here (9128300) because I rebased and screwed up the history.

Copy link
Contributor

@pragl pragl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A few small recommendations, but the docs look good!

The `actual_cost_mode` option allows you to choose how the actual cost of an operation is calculated.

* `by_subgraph` (default for Router versions >= v2.12.0) sums the cost of each subgraph response. This method reflects
* `by_subgraph` (default for Router versions &ge;v2.12.0) sums the cost of each subgraph response. This method reflects
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* `by_subgraph` (default for Router versions &ge;v2.12.0) sums the cost of each subgraph response. This method reflects
- `by_subgraph` (default for Router versions &ge;v2.12.0) sums the cost of each subgraph response. This method reflects

Base automatically changed from caroline/demand-control-actuals to dev February 3, 2026 23:13
Copy link
Contributor

@pragl pragl left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@carodewig carodewig merged commit 1737afd into dev Feb 9, 2026
15 checks passed
@carodewig carodewig deleted the caroline/demand-control-by-subgraph branch February 9, 2026 16:01
@abernix abernix mentioned this pull request Feb 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants