October 7, 2026

Introducing GraphOS Router 3.0

Matthew Ratzke

Matthew Ratzke

GraphOS Router runs your graph, bringing data from its services together into an API your apps can use. With GraphOS Router 3.0, launching today in Preview, we’re putting more control in the hands of the teams that build and run that API. We’re expanding Graph Artifacts, improving query planning, and adding native circuit breaking. We’ve also rewritten the request pipeline and improved JSON handling, with changes to the core engine that serves your graph.

More control over startup and deployment

Graph Artifacts package your supergraph schema as a version you can choose, test, and deploy. In GraphOS Router 3.0, we’re adding persisted queries to that package and removing the need to reach Apollo’s management plane at startup when you’ve supplied the required artifacts. That means you can deliver what the router needs through your own infrastructure, using the process your team already follows for a release. You choose when a new version goes live and can return to a known version if you need to roll back. The schema and persisted queries become part of the deployment, giving you more control over how your router fleet starts.

Improvements through the request path

Router 3.0 introduces an incremental query planner that builds a complete plan field by field, then improves it within a set search budget. When several services can resolve a field, it compares routes and favors plans with fewer fetches and shorter chains of dependent calls. The planner algorithm will backtrack and try other routes searching for better paths. This constrains the search for a better plan and reduces the memory spent exploring alternatives. For very large queries, the planner is up to 300 times faster while using 97% less memory. To learn more, read the Incremental Query Planner deep dive blog.

We’ve also rewritten the request pipeline around reusable Tower services, the Rust components that process each stage of a request. These services can be cloned, removing internal buffers that were previously needed to share access to a service. Readiness checks let downstream stages signal when they cannot accept more work, allowing backpressure to flow through the pipeline. Removing those extra queues reduces the handoffs and coordination needed to move a request through the router.

On the response side, the router avoids repeated work over JSON data while collecting usage metrics. When it processes GraphQL fragments, it tracks response objects by their memory address instead of hashing their contents each time. This avoids repeatedly walking large JSON subtrees just to check whether a fragment has already been processed for an object. The reported data stays the same, with less CPU work on large responses that contain many fragments.

Circuit breaking built into the GraphOS Router

Also coming soon to Router 3.0, we are adding native circuit breaking for subgraphs and Apollo Connectors, so the router can stop sending work to a service that is reporting failures. When a set failure threshold is reached, the breaker pauses those requests and later sends a probe to check whether the service has recovered. This gives the service room to recover and helps prevent failures from spreading through the graph. Teams can set thresholds for individual services and use telemetry to see when a breaker opens, rejects requests, or checks for recovery.

Every subgraph and Apollo Connector features its own circuit breaker, allowing traffic to flow normally while monitoring errors in a closed state. Should downstream failures cross your set threshold, the breaker trips to open, promptly returning errors to clients and shielding that service from further traffic. Following a brief pause, the router enters a half-open state and dispatches a single probe request while holding back other work. A successful probe closes the breaker to restore standard operation, whereas a failed attempt reopens it to give the underlying service more room to recover.

Distributed rate limiting

Distributed rate limiting is coming to Router 3.0, with a shared traffic limit across GraphOS Router instances. We’re using Redis to track that limit for routers that share the same policy and store. Each router draws from the same budget when it checks whether to allow an operation. Which means a limit will be enforced across the entire router fleet whether you run two routers or twenty. You can add router capacity without raising the load your services need to handle.

You’ll be able to set limits for each client, so you can choose which budget applies. Each tenant could have its own allowance, so one tenant’s traffic doesn’t use up another’s share. You’ll be able to limit incoming GraphQL operations as well as downstream calls to subgraphs and Apollo Connectors. That gives you control over traffic entering the graph and the work sent to your services.

We’re working towards an observation mode that shows which requests a proposed policy would reject. It will check the limit and record that decision, while leaving enforcement off for that policy. You can see which callers would be affected, adjust the limit, and test it against real traffic before you enforce it.

Updated to support the latest GraphQL Specification

We’re bringing Router 3.0 up-to-date with the latest GraphQL specification. This includes support for the built-in @oneOf directive for modeling mutually exclusive inputs. Marking an input object with @oneOf will require clients to submit exactly one of the input fields, enforced by the Router during operation validation. Previously, this would require custom validations in your subgraphs. Now you can shift the errors left and have the Router reject invalid queries before sending any traffic downstream. The @oneOf directive is supported in Composition v3, which you can try out by switching to the Federation Next build track in GraphOS.

The latest GraphQL specification also includes new validations for the @deprecated directive. The reason argument is now non-nullable. Previously, nullifying the argument with @deprecated(reason: null) was valid, introducing ambiguity in the meaning of the directive. Some libraries considered this to mean the field was not deprecated, while others meant it to mean the field was deprecated without a reason. The latest spec removes the ambiguity altogether. Additionally, if you have an object type which implements an interface and you deprecate one of the object’s fields, the corresponding interface field must also be deprecated. This prevents dropping implementer fields when clients continue to rely on the related interface. Both of these patterns will be patched in the LTS version of Federation and raised as hints in the build system so you can try out Router 3.0 with your existing supergraph. These validations will be enforced in Federation 3.

Finally, GraphOS Router 3.0 supports the other quality of life improvements from the GraphQL specification. You can now add descriptions to operation definitions, allowing you to describe your queries and fragments. This is especially useful for AI agents to get more context about how an operation is used and when to call it. Comments and strings in GraphQL documents now also support Unicode characters above 0xFFFF 🚀. These updates should allow you to write more expressive schemas while safely evolving your schema without disrupting clients.

Where to go next 

GraphOS Router 3.0 gives teams more control over how they deploy and operate their graph, while strengthening the performance and resilience of the infrastructure underneath it.

If you’re already running GraphOS Router 2.x, you can start trying Router 3.0 in Preview today. Read the GraphOS Router 3.0 documentation to explore what’s new, and follow the upgrade guide for everything you need to move from Router 2.x to Router 3.0.

Written by

Matthew Ratzke

Matthew Ratzke

Read more by Matthew Ratzke