Router Configuration Reference
The Router is configured via a YAML file (router.yaml). This reference covers the most common configuration options.
Basic Structure (v2 default)
supergraph:
listen: 127.0.0.1:4000
introspection: true
path: /graphql
sandbox:
enabled: true
homepage:
enabled: false
cors:
allow_any_origin: true # development only
headers:
all:
request:
- propagate:
matching: ".*"
telemetry:
# ... telemetry configBasic Structure (v1 legacy)
cors:
origins:
- "*"Supergraph Configuration
supergraph:
# Address to listen on
listen: 127.0.0.1:4000
# GraphQL endpoint path
path: /graphql
# Enable introspection queries
introspection: true
# Query planning options
query_planning:
# Enable query plan caching
cache:
in_memory:
limit: 512Sandbox and Introspection
# Apollo Sandbox (GraphQL IDE)
sandbox:
enabled: true # Disabled by default in production
# Introspection (required for Sandbox)
supergraph:
introspection: true # Disabled by default in productionFor development mode, both are enabled automatically with --dev.
CORS Configuration
v1 vs v2: CORS schemas are incompatible. See divergence-map.md for details.
v1 (flat schema)
cors:
origins:
- http://localhost:3000
- https://studio.apollographql.com
allow_headers:
- Content-Type
- Authorization
methods:
- GET
- POST
- OPTIONS
allow_credentials: true
max_age: 24h # duration stringv2 (policies schema)
cors:
allow_credentials: true
methods:
- GET
- POST
- OPTIONS
max_age: 24h # duration string, not integer
policies:
- origins:
- http://localhost:3000
- https://studio.apollographql.com
allow_headers:
- Content-Type
- AuthorizationSubgraph Configuration
# Override subgraph URLs (useful for local development)
override_subgraph_url:
products: http://localhost:4001/graphql
reviews: http://localhost:4002/graphql
# Subgraph-specific settings
traffic_shaping:
all:
timeout: 30s
subgraphs:
products:
timeout: 60s # Override for slow subgraphTraffic Shaping
traffic_shaping:
# Apply to all subgraphs
all:
# Request timeout
timeout: 30s
# Rate limiting
global_rate_limit:
capacity: 1000
interval: 1s
# Router-level settings
router:
timeout: 60s
# Per-subgraph settings
subgraphs:
slow-service:
timeout: 120sAuthentication (JWT)
v1 vs v2: The
issuerfield was renamed toissuers(plural array) in v2.issueris v1-only.
v1
authentication:
router:
jwt:
jwks:
- url: https://auth.example.com/.well-known/jwks.json
issuer: https://auth.example.com/ # singular string
authorization:
require_authentication: truev2
authentication:
router:
jwt:
jwks:
- url: https://auth.example.com/.well-known/jwks.json
issuers: # plural array
- https://auth.example.com/
authorization:
require_authentication: trueAuthorization Directives (field-level)
authorization.require_authentication above is an all-or-nothing gate on the whole request. For field- and type-level access control, use the declarative authorization directives — @authenticated, @requiresScopes, and @policy — applied in your subgraph schemas. The router filters out unauthorized fields before query planning and returns UNAUTHORIZED_FIELD_OR_TYPE errors for them.
GraphOS feature. Requires a router connected to GraphOS — Router v1.29.1+; on Developer/Standard plans, Router v2.6.0+. The directives need a claims source: configure JWT authentication (claims land at the
apollo::authentication::jwt_claimscontext key) or inject claims with a coprocessor.
Enabled by default. The directives are on as soon as your router is GraphOS-connected and your schema uses them. Config only disables them:
authorization:
directives:
enabled: false # default is true — only set this to turn directives OFFThe directives themselves live in subgraph schemas, imported via @link:
extend schema
@link(url: "https://specs.apollo.dev/federation/v2.6",
import: ["@authenticated", "@requiresScopes", "@policy"])
type Query {
me: User @authenticated
users: [User!]! @requiresScopes(scopes: [["read:others"]])
}
type User {
id: ID!
email: String @requiresScopes(scopes: [["read:email"]])
creditCard: String @policy(policies: [["read_credit_card"]])
}@authenticated— field requires any valid identity (claims present).@requiresScopes(scopes: [[...]])— requires specific scopes. Inner array = AND, outer array = OR. Reads thescopekey (space-separated string) from the claims object.@policy(policies: [[...]])— custom authorization. Requires a Supergraph plugin (Rhai script or coprocessor): the router populatesapollo::authorization::required_policiesas apolicy -> nullmap, and your plugin sets each totrue/false. Unset (null) is treated asfalse.
Context key differs by version (relevant if a coprocessor reads claims): v2 uses
apollo::authentication::jwt_claims; v1 usedapollo_authentication::JWT::claims. See divergence-map.md.
Response Caching (v2.6.0+)
Response caching uses the
response_cachetop-level key (notsupergraph.cache). See response-caching.md for full setup, schema directives, invalidation, and observability.
# Minimal response caching setup
response_cache:
enabled: true
subgraph:
all:
enabled: true
ttl: 5m
redis:
urls: ["redis://localhost:6379"]Automatic Persisted Queries (APQ)
Performance only — not a security control. APQ lets clients send the SHA-256 hash of an operation instead of the full string to save bandwidth. The router caches any operation it receives at runtime, so APQ does not restrict which operations can run. For an operation allowlist, use Persisted Query Safelisting below — and note the two are mutually exclusive.
apq:
enabled: true
router:
cache:
in_memory:
limit: 512
# Or Redis
# redis:
# urls:
# - redis://localhost:6379Persisted Query Safelisting (PQL)
Security control, distinct from APQ. Clients register trusted operations to a GraphOS-managed Persisted Query List (PQL) at build time (via
rover persisted-queries publishin their CI/CD). The router fetches the PQL on startup and can reject any operation not on the list. Requires a router connected to GraphOS (APOLLO_KEY+APOLLO_GRAPH_REF), orlocal_manifestsfor offline licenses.Config key: GA
persisted_queriessince v1.32.0 (waspreview_persisted_queriesin v1.25.0–v1.32.0); GA in all v2.
Adopt incrementally — start in audit mode, then enforce once you confirm all clients are registered.
Audit mode (logs unregistered operations, rejects nothing):
persisted_queries:
enabled: true
log_unknown: trueSafelisting (rejects unregistered operations; registered IDs and full strings both accepted):
persisted_queries:
enabled: true
safelist:
enabled: true
apq:
enabled: false # REQUIRED: APQ and safelisting are mutually exclusiveSafelisting, IDs only (also rejects freeform operation strings, even registered ones):
persisted_queries:
enabled: true
safelist:
enabled: true
require_id: true
apq:
enabled: falseOffline / air-gapped (use a local manifest instead of fetching from GraphOS Uplink):
persisted_queries:
enabled: true
local_manifests:
- ./persisted-query-manifest.json
hot_reload: true # optional: reload the manifest file on change (local_manifests only)You can opt individual requests out of enforcement from a Rhai script or coprocessor by setting the apollo_persisted_queries::safelist::skip_enforcement context key to true.
Limits and Security
limits:
# Maximum request body size
http_max_request_bytes: 2000000 # 2MB
# Query complexity limits
max_depth: 15
max_height: 200
max_aliases: 30
max_root_fields: 20Include Subgraph Errors
# Control which subgraph errors are exposed to clients
include_subgraph_errors:
all: true # Include all subgraph errors (development)
# Or selectively
# all: false
# subgraphs:
# products: true # Only expose products errorsSubscriptions
subscription:
enabled: true
mode:
# WebSocket-based subscriptions
passthrough:
all:
path: /ws
# Or callback-based
# callback:
# public_url: https://router.example.com/callbackDevelopment vs Production
Development Configuration
# router.dev.yaml
supergraph:
introspection: true
sandbox:
enabled: true
include_subgraph_errors:
all: true
telemetry:
exporters:
logging:
stdout:
enabled: true
format: textProduction Configuration
# router.prod.yaml
supergraph:
listen: 0.0.0.0:4000
introspection: false
sandbox:
enabled: false
homepage:
enabled: false
health_check:
enabled: true
listen: 0.0.0.0:8088
path: /health
include_subgraph_errors:
all: false
# CORS — use v1 or v2 format as appropriate (see CORS section above)
cors:
origins:
- https://app.example.com
telemetry:
exporters:
tracing:
otlp:
enabled: true
endpoint: http://collector:4317For complete production templates with all features, see:
Environment Variable Expansion
Use environment variables in configuration:
supergraph:
listen: ${env.ROUTER_LISTEN_ADDRESS:-127.0.0.1:4000}
override_subgraph_url:
products: ${env.PRODUCTS_URL}
authentication:
router:
jwt:
jwks:
- url: ${env.JWKS_URL}Configuration Validation
Validate configuration without starting the Router:
router config validate router.yaml