Skip to content

Federation routers

GraphPilot does not compose subgraphs. It sits in front of your router or gateway, which keeps doing the composition and query planning it already does. To GraphPilot, the router is the origin of one service, and the composed schema is that service’s schema.

client → GraphPilot → your router or gateway → subgraphs

This works with any router that speaks GraphQL over HTTP: Apollo Router, Cosmo Router, Hive Gateway, or your own gateway. It is available on every plan.

A deployment is built from a schema.graphql file next to your gpilot.toml (see deployments). For a federated graph, that file is the composed schema: the one your router serves to clients, not a single subgraph’s.

Your composition tool produces it, whether that is Rover, the Cosmo CLI, Hive, or a script of your own. Write it to schema.graphql as part of the same pipeline that publishes a new composition to your router, so GraphPilot and the router always run the same schema. See Deploy from CI for the GraphPilot half of that pipeline. Deploy to GraphPilot first and publish to the router after it: while the router serves fields the deployed schema does not declare, a query selecting them is answered but never cached (CACHE_SKIPPED_UNRESOLVED_SELECTION). See deploy the schema before the origin.

Entity keys work without extra setup when your types have an id, _id or key field, or any field of type ID. If your entities are keyed on other fields, tell GraphPilot which ones with @surrogateKey, or map an existing directive to it.

GraphPilot takes a response’s cache policy from one of two places, in this order (see how long an entry lives):

  1. A Cache-Control header on the router’s response. If your router sends one, for example because it passes on or computes a header from what the subgraphs return, GraphPilot follows it. Check what your router actually sends before relying on it: send a query straight to the router and read the response headers.
  2. @cacheControl hints in the schema.graphql you deploy. GraphPilot reads them from that file, not from the router or the subgraphs. Hints written in a subgraph only count if your composition keeps them in the composed schema (in Apollo Federation 2, a directive has to be marked with @composeDirective for that).

If neither is there, nothing is cached.

GraphPilot signs every request it forwards with your service’s signing key (see request signing). With a router behind it, the request GraphPilot signs is the one that reaches the router. Your subgraphs receive new requests the router makes, which carry no GraphPilot signature.

So verify at the first hop GraphPilot talks to:

  • In the router, through whatever extension point it offers for inspecting an incoming request with its body: a plugin, a coprocessor, or a custom module. Hive Gateway is built on GraphQL Yoga and takes plugins with the same onRequest hook, so the Yoga plugin is a starting point there.
  • In a reverse proxy in front of the router, if the router has no suitable hook. The proxy checks the signature and forwards only requests that pass.

Either way, the check needs the raw request body, the method, the path with its query string, and the gp-timestamp and gp-signature headers, exactly as described in verify the signature on your origin. To keep the subgraphs private as well, make them reachable only from the router.

Mutations sent through GraphPilot purge automatically, whichever subgraph resolves them. GraphPilot reads the keys of the objects in the mutation response and purges every cached response that contained them (see automatic invalidation). Let each mutation return the object it changed.

When a subgraph’s data changes outside GraphQL (a job, an import, another service writing to the same database), call the purge API from there. The API key needs the cache:purge permission.