# Apollo Router Core: a Rust gateway for a federated GraphQL supergraph

> Apollo Router Core is a Rust implementation of a graph router that serves an Apollo Federation 2 supergraph, replacing the Node based Apollo Gateway with a configurable binary. It is built around four stated design principles, ships Rhai and Rust extension examples, and publishes releases every one to two weeks.

**apollographql/router** — A configurable, high-performance routing runtime for Apollo Federation 🚀

- Repository: https://github.com/apollographql/router
- Website: https://www.apollographql.com/docs/router/
- Stars: 983 · Forks: 349
- Language: Rust
- License: NOASSERTION
- Published: 2026-10-20 · Updated: 2026-10-20 · Language: en
- Canonical page: https://hysenlabs.com/projects/apollographql-router

## A gateway that runs a supergraph, not a GraphQL server

Apollo Router Core is described as a configurable, high-performance graph router written in Rust to run a federated supergraph that uses Apollo Federation 2.

The word supergraph is the one to understand first. In a federated setup, you have several subgraphs, each owning part of the schema, and a router that composes them into one API and executes a query plan against them. The router is not a GraphQL server in the ordinary sense: it does not own a schema, it does not resolve fields against resolvers, it routes a plan that has already been derived.

That distinction is why the tool exists. The documentation states that Apollo Router Core is well-tested, regularly benchmarked, includes most major features of Apollo Gateway and is able to serve production-scale workloads. The Gateway is the Node implementation, and this is the Rust replacement for it, which means the same federation deployment is served by a different runtime.

The audience is a platform or API team, not an application developer. If you have one GraphQL API, you want a GraphQL server and Apollo Server is the thing named for that role. If you have thirty subgraph services composed into one graph, you want a router, and this is it.

The extension mechanism is what makes it more than a router library. The examples directory contains coprocessor examples in Rhai and Rust, plus rhai examples for cache control, context, cookies to headers, data response mutation, error response mutation, forbid anonymous operations, forbid mutations, jwt claims, logging, op name to header, status code propagation and subgraph request log. Both a scripting language and a native Rust path are supported, and the Cargo workspace lists them as separate example crates, so they are compiled and tested rather than being documentation sketches.

## Two inputs: a supergraph file and an optional config

The usage requirement is short and strict. Apollo Router Core requires a supergraph file to be passed as the --supergraph argument, and an optional configuration file to be supplied. Both are either located in the current directory or explicitly specified via flag, either by an absolute path or a path relative to the current directory.

The command line surface is what the help output shows, and it is worth reading because the environment variables are the deployment mechanism in practice.

```
  -c, --config <CONFIG_PATH>
          Configuration location relative to the project directory [env: APOLLO_ROUTER_CONFIG_PATH=]
      --dev
          Enable development mode [env: APOLLO_ROUTER_DEV=]
  -s, --supergraph <SUPERGRAPH_PATH>
          Schema location relative to the project directory [env: APOLLO_ROUTER_SUPERGRAPH_PATH=]
      --apollo-uplink-endpoints <APOLLO_UPLINK_ENDPOINTS>
          The endpoints (comma separated) polled to fetch the latest supergraph schema [env: APOLLO_UPLINK_ENDPOINTS=]
```

Every option has a matching environment variable, which is the point. In a container or a Kubernetes deployment you set APOLLO_ROUTER_SUPERGRAPH_PATH and APOLLO_ROUTER_CONFIG_PATH rather than assembling a command line.

Two flags deserve attention because they change behaviour rather than just paths.

The --hot-reload flag reloads locally provided configuration and supergraph files automatically, and the help text is careful about the limit: this only affects watching of local files and does not affect supergraphs and configuration provided by GraphOS through Uplink, which is always reloaded immediately. So there are two update paths, and the flag only accelerates one of them.

The --apollo-uplink-endpoints flag takes a comma separated list of endpoints polled to fetch the latest supergraph schema, with a companion --apollo-uplink-timeout that defaults to 30s. Polling is how a router picks up a new supergraph without a redeploy, which is the difference between a gateway you restart and a gateway that follows your schema registry.

There is also a config subcommand for configuration subcommands, and the flag --anonymous-telemetry-disabled turns off the anonymous usage ping without affecting usage reporting to Apollo Studio for graphs configured with APOLLO_KEY and APOLLO_GRAPH_REF.

## Four design principles that explain the configuration surface

The documentation sets out the principles that drive architecture decisions, and they are a better guide to how the router behaves than any individual configuration option.

Correctness is the first. The router strives to be the most correct implementation of GraphQL and Federation, the project cares about testing and documenting everything implied by the specification, up to failure cases, and behaviour should follow the principle of least surprise for developers.

Reliability is the second, and it is spelled out into three concrete properties. Stability, meaning no crashes, infinite loops or leaks. Availability, meaning predictable latency, RAM and CPU usage, and scalability. And observability, meaning metrics and alerts. The stated aim is to give infrastructure people strong confidence that they can learn its limits and operate it safely.

Safe experimentation is the third. Since the router will support all future work around Federation, it must allow new ideas without disturbing existing features, and the documentation is candid that the project is still in movement and cannot be allowed to crystallise too early while still following correctness and reliability.

Usability is the fourth, and it contains the most operational guidance. The router must be simple to operate, and the stated preference is extensibility over configuration options. Two examples follow. Common environmental misconfiguration should be detected and surfaced to the user in the form of mitigation steps, rather than failing obscurely. And user supplied extensions should be observable and flagged when they cause performance issues, with the users told how much time an extension is consuming per request and why.

That last point is the one most extensions frameworks ignore. A Rhai script that adds forty milliseconds per request should say so. In a router where extensions are the intended way to customise behaviour, being able to see the cost of your own customisation is not a nicety.

The prefer-extensibility-over-configuration stance also predicts the shape of any future option, and it is a deliberate trade: fewer knobs, more code, on the assumption that code is easier to review than a hundred configuration keys.

## Extensions in Rhai and Rust, and what they can reach

The examples directory is the best documentation of what the router lets you change, and it divides into two languages.

The Rhai examples are scripting extensions. They cover adding a timestamp header, async auth, cache control, context, cookies to headers, mutating data responses, mutating error responses, forbidding anonymous operations, forbidding mutations, reading jwt claims, logging, copying an operation name into a header, propagating status codes, and logging subgraph requests. Several of those, forbid anonymous operations and forbid mutations in particular, are policy rules, and the examples exist in both Rhai and Rust for some of them, which tells you the router does not consider either language second class for that job.

The Rust examples cover the cases where you need to own the type system or the async runtime: async auth, context, hello world, status code propagation, subgraph request log, supergraph SDL, surrogate cache key, and coprocessor subgraph.

The coprocessor examples are the most interesting. A coprocessor is an external process that the router calls out to, and there are examples of one driven over a Unix socket, one running as a separate subgraph service, one that overrides LaunchDarkly, and one general purpose coprocessor. That is a meaningfully different architectural option from scripting in-process: the coprocessor runs outside the router, which means it can be a Go, Python or Node service, can be scaled independently, and can hold state the router should not.

The workspace also includes a fuzz directory with a subgraph target, so the request handling path is fuzzed.

Two other features worth naming because they are hard to retrofit. The cache-control example implies the router can honour and propagate cache directives across subgraphs. And the surrogate cache key example implies it can compute a cache key that differs from the response body, which is what you need when the same query returns different content per user and the CDN in front of the router must not serve one user's response to another.

## A repository organised like a production service, not a library

The top level layout is that of a long-lived production service rather than a small crate.

There is apollo-router/ for the binary, apollo-federation/ with its own cli subcrate, apollo-router-benchmarks/, examples/, fuzz/, xtask/ for workspace tooling, dev-docs/, and a helm/ directory for Kubernetes deployment. There is also about.hbs, about.toml and licenses.html, which are the licence aggregation artefacts a project that vendors dependencies needs.

The build configuration in Cargo.toml has details that reflect a project that builds on CI every day. The dev profile sets debug = "line-tables-only", with a comment explaining that line tables keep file and line in backtraces while making rebuilds and the build output smaller, and that for full debug info you build with CARGO_PROFILE_DEV_DEBUG=true. The dev build override strips debuginfo and disables incremental compilation, with a note that build scripts and proc macros compile faster that way. There is a separate release-dhat profile for heap allocation tracing, with the comment that you must use it to build the dhat feature, and the example command lines for dhat-heap and dhat-ad-hoc.

There is a deny.toml for cargo-deny, which checks dependency licences and advisories, a .gitleaks.toml for secret scanning, and a .mergify.yml for automated merge handling.

The docker-compose.yml is a test harness rather than a demo. It runs a Datadog APM test agent, a standalone Redis, and four Redis cluster nodes on ports 7000 through 7003, each with cluster-enabled and protected-mode no. A comment explains the duplication: different integration tests focus on different modes of Redis, and in the future there should probably be Redis sentinel.

That composition is a good indicator of scope. The router supports single instance and clustered Redis for its cache, and the test suite exercises both, which is what you would expect from a gateway meant to run several replicas against shared cache state.

## Release cadence and where the licence question actually sits

The release history is fast and the versions overlap. v2.18.0 was tagged on 2026-09-30, v3.0.0-preview.0 on 2026-10-03 and v2.19.0-rc.0 on 2026-10-16. The default branch is dev-v3.x, which tells you the v3 line is under development while v2 is the stable series, and the presence of a v2.19 release candidate alongside a v3 preview means the two lines are being prepared in parallel.

The documentation states the cadence directly: new releases are published every one to two weeks. The CHANGELOG.md at the repository root contains unreleased changes in addition to the full history, and there is a RELEASE_CHECKLIST.md alongside it.

A one to two week release train has consequences. It means the project is moving fast and that you will be taking many upgrades, and it also means you should read the release notes, since the documentation points at them specifically for notes about breaking changes. For a gateway sitting in front of production traffic, a release every ten days is a maintenance commitment rather than a convenience.

On licensing, the licence field on the repository says Other, a custom licence GitHub cannot classify, and the root carries a LICENSE file. Apollo's router is not distributed under a standard open source licence in the way most Rust infrastructure is, so anyone planning to run it in production, and especially anyone who wants to modify it or offer it as a service, needs to read that LICENSE file and the licenses.html artefact directly. This is not legal advice, and the practical point is that a gateway which sits between clients and your services deserves a licence review before it goes anywhere near production traffic.

The last push was on 2026-10-20, so the tree is being worked on continuously.

## Conclusion

Apollo Router Core suits a team running a federated GraphQL supergraph in production who wants a gateway binary they can operate, extend and reason about in Rust rather than a Node service. It does not suit a project that has not yet federated its APIs, since the router consumes a supergraph schema and is not a GraphQL server in its own right, and it does not suit a team unwilling to accept a release train that moves every one to two weeks. Before adopting it, read the four design principles in the project documentation, because they explain most of the configuration trade-offs, and confirm your supergraph is Federation 2, since that is the version the router targets.

## FAQ

### What does Apollo Router Core require to run?

It requires a supergraph file passed as the --supergraph argument and an optional configuration file, each either in the current directory or specified by flag as an absolute or relative path. Every option also has an environment variable such as APOLLO_ROUTER_SUPERGRAPH_PATH and APOLLO_ROUTER_CONFIG_PATH.

### How does Apollo Router Core pick up a new supergraph schema?

Through Uplink, using the --apollo-uplink-endpoints flag with a comma separated list of endpoints polled to fetch the latest supergraph schema, and --apollo-uplink-timeout which defaults to 30s. The --hot-reload flag only accelerates reload of locally provided files and does not affect Uplink provided supergraphs, which are always reloaded immediately.

### Which languages can Apollo Router Core extensions be written in?

Rhai, a scripting language, and Rust. The examples directory and the Cargo workspace members include both, with examples such as forbid-anonymous-operations and forbid-mutations present in both languages, and coprocessor examples that run as a separate service over a Unix socket.

### How often does Apollo Router Core publish releases?

The documentation states that new releases are published every one to two weeks. Recent tags include v2.18.0 on 2026-09-30, v3.0.0-preview.0 on 2026-10-03 and v2.19.0-rc.0 on 2026-10-16, with the default branch being dev-v3.x.

### What licence applies to Apollo Router Core?

The licence field on the repository says Other, a custom licence GitHub cannot classify, and the root carries a LICENSE file along with a licenses.html artefact. The licence needs to be read directly rather than inferred from the repository metadata.

## Sources

- [apollographql/router on GitHub](https://github.com/apollographql/router)
- [Issues](https://github.com/apollographql/router/issues)
- [Project website](https://www.apollographql.com/docs/router/)
- [README](https://github.com/apollographql/router/blob/dev-v3.x/README.md)
- [Releases](https://github.com/apollographql/router/releases)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/apollographql-router
