{"id":"src_-X_uDC8Mebeh1ZYNvkY_Z","slug":"apollo-router","name":"Apollo Router","type":"github","url":"https://github.com/apollographql/router","orgId":"org_ctiL2ZZXIA7tbsKSsxRN9","org":{"slug":"apollo-graphql","name":"Apollo GraphQL"},"isPrimary":false,"metadata":"{\"evaluatedMethod\":\"github\",\"evaluatedAt\":\"2026-04-11T13:26:48.026Z\",\"changelogUrl\":\"https://github.com/apollographql/router/blob/HEAD/CHANGELOG.md\",\"changelogDetectedAt\":\"2026-04-11T13:27:37.649Z\"}","releaseCount":100,"releasesLast30Days":10,"avgReleasesPerWeek":1.5,"latestVersion":"v2.13.1","latestDate":"2026-04-03T18:43:23.000Z","changelogUrl":"https://github.com/apollographql/router/blob/HEAD/CHANGELOG.md","hasChangelogFile":true,"lastFetchedAt":"2026-04-19T07:02:19.812Z","trackingSince":"2025-03-25T17:27:35.000Z","releases":[{"id":"rel_XnVQ6cPxDP0CMyFiPwG4w","version":"v2.13.1","title":"v2.13.1","summary":"## 🐛 Fixes\n\n### Fix spurious `REQUEST_RATE_LIMITED` errors when no rate limiting is configured ([PR #9034](https://github.com/apollographql/router/pu...","content":"## 🐛 Fixes\n\n### Fix spurious `REQUEST_RATE_LIMITED` errors when no rate limiting is configured ([PR #9034](https://github.com/apollographql/router/pull/9034))\n\nUnder sustained load, the router could return `REQUEST_RATE_LIMITED` (429) errors even when no rate limiting was configured. An internal queue had an implicit limit that could trigger load shedding, even if the queue was not _actually_ overloaded.\n\nThis fix removes that implicit limit, so requests are shed only when the queue is genuinely full. The queue still has explicit limits to ensure quality of service.\n\nBy @jhrldev in https://github.com/apollographql/router/pull/9034\n","publishedAt":"2026-04-03T18:43:23.000Z","url":"https://github.com/apollographql/router/releases/tag/v2.13.1","media":[]},{"id":"rel_BDAOCwbwB7MqOsRqpFzAF","version":"v2.13.1-rc.0","title":"v2.13.1-rc.0","summary":"","content":"","publishedAt":"2026-04-01T04:56:55.000Z","url":"https://github.com/apollographql/router/releases/tag/v2.13.1-rc.0","media":[]},{"id":"rel_DzANtmO7jCtKk_m6TLU6H","version":"v2.13.0","title":"v2.13.0","summary":"## 🚀 Features\n\n### Add `context_id` selector for telemetry to expose unique per-request identifier ([PR #8899](https://github.com/apollographql/route...","content":"## 🚀 Features\n\n### Add `context_id` selector for telemetry to expose unique per-request identifier ([PR #8899](https://github.com/apollographql/router/pull/8899))\n\nA new `context_id` selector is now available for router, supergraph, subgraph, and connector telemetry instrumentation. This selector exposes the unique per-request context ID, which you can use to reliably correlate and debug requests in traces, logs, and custom events.\n\nThe context ID was previously accessible in Rhai scripts as `request.id` but had no telemetry selector. You can now include `context_id: true` in your telemetry configuration to add the context ID to spans, logs, and custom events.\n\nExample configuration:\n\n```yaml\ntelemetry:\n  instrumentation:\n    spans:\n      router:\n        attributes:\n          \"request.id\":\n            context_id: true\n      supergraph:\n        attributes:\n          \"request.id\":\n            context_id: true\n      subgraph:\n        attributes:\n          \"request.id\":\n            context_id: true\n      connector:\n        attributes:\n          \"request.id\":\n            context_id: true\n```\n\nBy @BobaFetters in https://github.com/apollographql/router/pull/8899\n\n### Enable Unix Domain Socket paths ([PR #8894](https://github.com/apollographql/router/pull/8894))\n\nEnables Unix Domain Socket (UDS) paths for both coprocessors and subgraphs. Paths must use `?path=` as the query param: `unix:///tmp/some.sock?path=some_path`\n\nBy @aaronarinder in https://github.com/apollographql/router/pull/8894\n\n### Add configurable `pool_idle_timeout` for HTTP client connection pools ([PR #9014](https://github.com/apollographql/router/pull/9014))\n\nAdds a new `pool_idle_timeout` configuration option to the HTTP client used by subgraphs, connectors, and coprocessors. This controls how long idle keep-alive connections remain in the connection pool before being evicted. The default is 15 seconds (up from the previous hardcoded 5 seconds). Setting it to `null` disables the idle eviction interval entirely, meaning pooled connections are never evicted due to idleness.\n\nThe option is available at every level where HTTP client configuration applies:\n\n```yaml\ntraffic_shaping:\n  all:\n    pool_idle_timeout: 30s      # applies to all subgraphs\n  subgraphs:\n    products:\n      pool_idle_timeout: 60s    # per-subgraph override\n  connector:\n    all:\n      pool_idle_timeout: 30s    # applies to all connectors\n    sources:\n      my_source:\n        pool_idle_timeout: 60s  # per-source override\n\ncoprocessor:\n  url: http://localhost:8081\n  client:\n    pool_idle_timeout: 30s      # coprocessor client\n```\n\nBy @aaronarinder in https://github.com/apollographql/router/pull/9014\n\n### Add persisted query ID context key ([PR #8959](https://github.com/apollographql/router/pull/8959))\n\nAdds a context key for the persisted query ID in the router. The `PersistedQueryLayer` now stores the persisted query ID in the request context, and the Rhai engine can access it via that key.\n\nBy @faisalwaseem in https://github.com/apollographql/router/pull/8959\n\n### Add retry layer for push metrics exporters ([PR #9036](https://github.com/apollographql/router/pull/9036))\n\nAdds a `RetryMetricExporter` layer that retries up to three times with jittered exponential backoff for the `apollo metrics` and `otlp` named exporters.\n\nBy @rohan-b99 in https://github.com/apollographql/router/pull/9036\n\n## 🐛 Fixes\n\n### Support more types of nullable elements in response/entity cache keys ([PR #8923](https://github.com/apollographql/router/pull/8923))\n\n[PR #8767](https://github.com/apollographql/router/pull/8767) (released in Router v2.11.0) changed the entity and response caching keys to support nullable elements. The implementation covered the case of a field explicitly being set to null, but didn't cover the following cases:\n\n- Nullable field being missing\n- Nullable list items\n\nThis change adds support for those cases.\n\nBy @carodewig in https://github.com/apollographql/router/pull/8923\n\n### Pin transitive `h2` dependency at minimum v0.4.13 to pick up critical flow-control, deadlock, and tracing fixes ([PR #9033](https://github.com/apollographql/router/pull/9033))\n\n`h2` 0.4.13 (released January 5, 2026) contains three fixes directly relevant to the router, which uses h2 exclusively as a client when connecting to subgraphs:\n\n- **Capacity deadlock under concurrent streams ([#860](https://github.com/hyperium/h2/pull/860)) — high relevance:** Under concurrent load with `max_concurrent_streams` limits in effect, flow-control capacity could be assigned to streams still in `pending_open` state. Those streams could never consume the capacity, starving already-open streams and permanently freezing all outgoing traffic on the connection with no error surfaced. This is directly triggerable in the router: any subgraph behind Envoy or a gRPC backend advertises a `max_concurrent_streams` limit (Envoy defaults to 100), and under production load the router will routinely queue more concurrent requests than that limit allows.\n\n- **OTel tracing span lifetime leak ([#868](https://github.com/hyperium/h2/pull/868)) — high relevance:** The h2 `Connection` object captured the active tracing span at connection creation time as its parent, keeping that span alive for the entire lifetime of the connection. Since the router wraps every subgraph request in an OpenTelemetry span and connections are pooled, affected spans could linger indefinitely under sustained traffic — never being exported to the tracing backend and accumulating in memory.\n\n- **Flow-control stall on padded DATA frames ([#869](https://github.com/hyperium/h2/pull/869)) — lower relevance for typical subgraphs, higher for connectors:** Padding bytes in `DATA` frames were not being returned to the flow-control window, causing the connection window to drain to zero and permanently stalling downloads with no error. Typical GraphQL/gRPC subgraphs do not send padded frames, but router connectors calling arbitrary HTTP APIs (e.g., Google Cloud Storage or CDN-backed endpoints) can encounter this.\n\nBy @theJC in https://github.com/apollographql/router/pull/9033\n\n### Return 503 for rate limit traffic shaping ([PR #9013](https://github.com/apollographql/router/pull/9013))\n\nReverts [PR #8765](https://github.com/apollographql/router/pull/8765).\n\nWhen the router's rate limit or buffer capacity is exceeded, it now returns HTTP 503 (Service Unavailable) instead of HTTP 429 (Too Many Requests).\n\nHTTP 429 implies that a specific client has sent too many requests and should back off. HTTP 503 more accurately reflects the situation: the router is temporarily unable to handle the request due to overall service load, not because of the behavior of any individual client.\n\nThis change affects both router-level and subgraph-level rate limiting. Documentation has been updated to reflect the new status code.\n\nBy @carodewig in https://github.com/apollographql/router/pull/9013\n\n### Set `Cache-Control: no-store` when the response cache returns GraphQL errors ([PR #8933](https://github.com/apollographql/router/pull/8933))\n\nWhen using the response cache plugin, if a query spans multiple subgraphs and one returns an error or times out, the final HTTP response was still carrying the successful subgraph's `Cache-Control` header (e.g. `max-age=1800, public`). This allowed intermediate caches (CDNs, reverse proxies) to cache and serve incomplete or stale partial responses to other clients.\n\nIf the response cache plugin is enabled and was going to set a `Cache-Control` header, but the response contains any GraphQL errors, it now sets `Cache-Control: no-store` instead of the merged subgraph cache control value.\n\nBy @carodewig in https://github.com/apollographql/router/pull/8933\n\n### Apply entity-less subgraph errors to the nearest parent instead of every entity\n\nWhen making an entity resolution, if entity resolution fails (for example, because the path from the subgraph was malformed), the router applied errors to every item in the list of entities expected. For example, if 2000 entities were expected but 2000 errors were returned instead, each error was applied to every entity. This causes an explosion of errors and leads to significant memory allocations that can cause OOMKills.\n\nWhen the router can't determine where an error should be applied, it now applies it to the most immediate parent of the targeted entity — for a list of users, it applies to the list itself rather than to each index of that list.\n\nBy @aaronArinder in https://github.com/apollographql/router/pull/8962\n\n### Report `http.client.response.body.size` and `http.server.response.body.size` consistently when `content-length` is absent or compression is used ([PR #8972](https://github.com/apollographql/router/pull/8972))\n\nReporting these metrics previously relied on either the `Content-Length` header or the `size_hint` of the body, which reports the uncompressed size. [OpenTelemetry semantic conventions](https://opentelemetry.io/docs/specs/semconv/http/http-metrics/#metric-httpclientrequestbodysize) recommend reporting the compressed size.\n\nThe router now consistently reports the compressed size when compression is used, even when `Content-Length` is absent, for:\n\n- Router → client responses\n- Subgraph → router responses\n- Connector → router responses\n\nBy @rohan-b99 in https://github.com/apollographql/router/pull/8972\n\n### Ensure query planning allocation stats are still recorded if cooperative cancellation is not enabled ([PR #8902](https://github.com/apollographql/router/pull/8902))\n\nThe metric `apollo.router.query_planner.memory` was unintentionally only showing allocations during the `query_parsing` compute job if cooperative cancellation for query planning was not enabled. Both `query_parsing` and `query_planning` should now be available.\n\nBy @rohan-b99 in https://github.com/apollographql/router/pull/8902\n\n### Align `ServiceMonitor` naming with other chart resources using the `router.fullname` helper ([Issue #TSH-22160](https://github.com/apollographql/router/issues/TSH-22160))\n\nThe `ServiceMonitor` Helm resource was using `.Release.Name` directly as its `metadata.name`, while all other chart resources (e.g. `Service`, `Deployment`) already used the `router.fullname` helper. This caused a naming inconsistency: for a release named `my-release`, the `Service` would be named `my-release-router` but the `ServiceMonitor` would be named `my-release`.\n\nThis change aligns the `ServiceMonitor` name with the rest of the chart by using `{{ include \"router.fullname\" . }}`, ensuring consistent naming and proper support for `nameOverride` and `fullnameOverride` values.\n\nBy @mateusgoettems in https://github.com/apollographql/router/pull/8929\n\n### Return null data and respect error location config for fully-unauthorized requests ([PR #9022](https://github.com/apollographql/router/pull/9022))\n\nWhen the query planner rejected a request because all fields were unauthorized, the response always placed errors in the `errors` array and returned `data: {}`, ignoring the configured `errors.response` location (`errors`, `extensions`, or `disabled`). The router now returns `data: null` and respects `errors.response` and `errors.log`, consistent with partially-unauthorized requests.\n\nBy @carodewig in https://github.com/apollographql/router/pull/9022\n\n### Handle both `deprecated` enum values when merging coprocessor context ([PR #8913](https://github.com/apollographql/router/pull/8913))\n\nA change to coprocessor context merges in Router v2.10 caused keys to be deleted when `context: true` is used as the coprocessor context selector in the router configuration file.\n\nThe workaround was to pass `context: deprecated` instead. This change brings parity when `context: true` is provided.\n\nBy @carodewig in https://github.com/apollographql/router/pull/8913\n\n### Block router startup when certain OTEL environment variables are set ([PR #8915](https://github.com/apollographql/router/pull/8915))\n\nThe router now fails to start if any of the following OpenTelemetry (OTEL) environment variables are set:\n\n- `OTEL_EXPORTER_OTLP_ENDPOINT`\n- `OTEL_EXPORTER_OTLP_TRACES_ENDPOINT`\n- `OTEL_EXPORTER_OTLP_METRICS_ENDPOINT`\n\nUsing these variables isn't supported by the router because they can override or interfere with its built-in telemetry configuration, leading to unexpected behavior.\n\nPreviously, the router emitted a warning when `OTEL_EXPORTER_OTLP_ENDPOINT` was present. Startup is now blocked to prevent unintended telemetry configuration conflicts.\n\nIf your deployment defines any of these environment variables (for example, through base container images, platform defaults, or infrastructure tooling), remove them before starting the router.\n\nBy @OriginLeon in https://github.com/apollographql/router/pull/8915\n\n### Prevent the readiness ticker from resetting the sampling window clock on recovery ([PR #8966](https://github.com/apollographql/router/pull/8966))\n\nThe readiness ticker recreated its `interval_at` inside the recovery loop on every cycle, which reset the sampling window clock each time the router returned to ready. This caused inconsistent sampling behavior across recovery cycles. Additionally, the rejection counter was read and zeroed with separate atomic operations (`load` + `store(0)`), leaving a race window where rejections arriving between the two operations could be silently dropped.\n\nThe fix creates the interval once outside the loop, sets `MissedTickBehavior::Delay` to prevent catch-up ticks after the recovery sleep, and uses `swap(0, Relaxed)` to atomically read and reset the rejection counter in a single operation.\n\nBy @OriginLeon in https://github.com/apollographql/router/pull/8966\n\n### Ensure `http2only` uses h2c for cleartext connections ([PR #9018](https://github.com/apollographql/router/pull/9018))\n\n`hyper` does not support [upgrading cleartext connections from HTTP/1.1 to HTTP/2](https://github.com/hyperium/hyper/issues/2411). To use HTTP/2 without TLS, clients must use 'prior knowledge' — connecting with the HTTP/2 preface directly. This is what `experimental_http2: http2only` is for, but previously HTTP/1 was always enabled in the connector, causing the client to fall back to HTTP/1.1 regardless. This fix applies to all outbound HTTP connections: subgraphs, connectors, and coprocessors.\n\n| `experimental_http2` | TLS | protocol used                                 |\n|----------------------|-----|-----------------------------------------------|\n| `disable`            | yes | HTTP/1.1                                      |\n| `disable`            | no  | HTTP/1.1                                      |\n| `enable`             | yes | HTTP/2 (if server supports it), else HTTP/1.1 |\n| `enable`             | no  | HTTP/1.1                                      |\n| `http2only`          | yes | HTTP/2                                        |\n| `http2only`          | no  | HTTP/2 (h2c — cleartext prior knowledge)      |\n\nBy @carodewig in https://github.com/apollographql/router/pull/9018\n\n### Reject invalid values for client library name and version ([PR #8934](https://github.com/apollographql/router/pull/8934))\n\nRejects invalid values (validated against a regex) for library name and version provided in headers or operation extensions, which are used for the Client Awareness feature and telemetry.\n\nBy @BoD in https://github.com/apollographql/router/pull/8934\n\n### Correct `no-store` and `no-cache` behavior for response cache and entity cache plugins ([PR #8948](https://github.com/apollographql/router/pull/8948) and [PR #8952](https://github.com/apollographql/router/pull/8952))\n\n`no-store` and `no-cache` have different meanings. Per [RFC 9111](https://datatracker.ietf.org/doc/html/rfc9111#name-cache-control):\n\n- `no-store`: allows serving a response from cache, but prohibits storing the response in cache\n- `no-cache`: prohibits serving a response from cache, but allows storing the response in cache\n\n(Note: `no-cache` actually prohibits serving a response from cache without revalidation — but the router doesn't distinguish between lookup and revalidation.)\n\nThe response caching and entity caching plugins were incorrectly treating `no-store` as both 'no serving response from the cache' and 'no storing response in the cache.' This change corrects that behavior.\n\nBy @carodewig in https://github.com/apollographql/router/pull/8948 and https://github.com/apollographql/router/pull/8952\n\n### Allow `exists` conditions with `request_header` selectors on response-stage coprocessor and event configurations ([PR #8964](https://github.com/apollographql/router/pull/8964))\n\nUsing `exists: { request_header: <name> }` as a condition on response-stage coprocessor or telemetry event configurations (e.g. `on: response`) previously caused the router to reject the configuration at startup with a validation error, even though the condition is valid and works correctly at runtime.\n\nThe validator was incorrectly rejecting request-stage selectors inside `Exists` conditions for response-stage configurations. This is safe because `evaluate_request()` pre-resolves these conditions before they are stored for response-time evaluation: if the header is present the condition becomes `True`; if absent, the event or coprocessor call is discarded and never reaches the response stage.\n\nBy @OriginLeon in https://github.com/apollographql/router/pull/8964\n\n## 📃 Configuration\n\n### Enable the router to pull graph artifacts from insecure (non-SSL) registries\n\nYou can configure a list of safe registry hostnames to enable the router to pull graph artifacts over HTTP instead of HTTPS. Insecure registries are commonly run within a private network such as a Kubernetes cluster or as a pull-through cache, where you want to avoid the overhead of setting up and distributing SSL certificates.\n\nBy @sirddoger in https://github.com/apollographql/router/pull/8919\n\n## 🛠 Maintenance\n\n### Update to OpenTelemetry 0.31.0 ([PR #8922](https://github.com/apollographql/router/pull/8922))\n\nThe router now uses v0.31.0 of the OpenTelemetry Rust libraries. This update includes many bug fixes and performance improvements from upstream.\n\nThe router doesn't guarantee the stability of downstream pre-1.0 APIs, so users that directly interact with OpenTelemetry must update their code accordingly.\n\nAs part of this upgrade, Zipkin Native exporter is [deprecated upstream](https://opentelemetry.io/blog/2025/deprecating-zipkin-exporters/). Switch to the OTLP exporter, which Zipkin now supports natively. Note that Zipkin Native exporter no longer supports setting a service name — if you need this, switch to the OTLP exporter.\n\nBy @BrynCooke @goto-bus-stop @rohan-b99 in https://github.com/apollographql/router/pull/8922\n\n### Use `cargo build --locked --release` in DIY `Dockerfile.repo` for deterministic, lockfile-respecting builds ([PR #8983](https://github.com/apollographql/router/pull/8983))\n\nThe DIY `Dockerfile.repo` previously used `cargo install --path apollo-router`, which doesn't enforce the versions in `Cargo.lock` — resulting in possible non-deterministic dependency resolution and builds that could diverge from what CI produces.\n\nUsing `cargo build --locked --release -p apollo-router` ensures the versions in the lockfile are respected and the DIY build path more closely aligns with CI.\n\nBy @theJC in https://github.com/apollographql/router/pull/8983\n\n## 📚 Documentation\n\n### Document AWS API Gateway support for HTTP multipart subscriptions\n\nUpdates the API gateway subscriptions documentation to reflect that Amazon API Gateway now supports response streaming for REST APIs. HTTP multipart subscriptions are supported when the router is behind AWS API Gateway. Includes a link to the AWS announcement (November 2025) and a short configuration note linking to Response transfer mode.\n\nBy @smyrick in https://github.com/apollographql/router/pull/8907\n\n### Add documentation for `experimental_hoist_orphan_errors` configuration\n\nAdds the `experimental_hoist_orphan_errors` configuration option to the YAML configuration reference. The documentation covers the feature's purpose (reducing multiplicative error propagation from entity resolution), per-subgraph and global enablement examples, the spec compliance caveat, and the known limitation that error counts are reduced but not hard-capped.\n\nBy @andywgarcia in https://github.com/apollographql/router/pull/8999\n\n### Document proxy root certificate configuration for router containers ([PR #8823](https://github.com/apollographql/router/pull/8823))\n\nDocuments how to add corporate proxy root certificates to Apollo Router containers — required for enterprise environments where TLS inspection proxies intercept HTTPS traffic.\n\nThe documentation includes:\n- Instructions for Docker deployments (runtime mount and custom image approaches)\n- Instructions for Kubernetes deployments (init container and custom image approaches)\n- Guidance for cloud deployments (AWS, Azure, GCP)\n- Links added to all containerization deployment guides\n\nBy @the-gigi-apollo in https://github.com/apollographql/router/pull/8823\n\n### Correct JWT authentication example hierarchy in the router authentication guide\n\nUpdates the GraphOS Router authentication guide to use the correct JWT configuration path in the YAML example. The example now shows `authentication.router.jwt.jwks` and `authentication.router.jwt.on_error`, matching the actual router configuration hierarchy.\n\nBy @the-gigi-apollo in https://github.com/apollographql/router/pull/8901\n\n### Document `http_client` span attribute limitations ([PR #8967](https://github.com/apollographql/router/pull/8967))\n\nDocuments that `http_client` span attributes don't support conditions or the `static` selector, causing a router startup failure when attempted.\n\nBy @mabuyo in https://github.com/apollographql/router/pull/8967\n\n## 🧪 Experimental\n\n### Add `experimental_hoist_orphan_errors` configuration for controlling orphan error path assignment\n\nAdds a new `experimental_hoist_orphan_errors` configuration that controls how entity-less (\"orphan\") errors from subgraphs are assigned paths in the response. When enabled for a subgraph, orphan errors are assigned to the nearest non-array ancestor in the response path, preventing them from being duplicated across every element in an array. This can be enabled globally via `all` or per-subgraph via the `subgraphs` map. Per-subgraph settings override `all`.\n\nHere's an example when targeting a specific subgraph, `my_subgraph`:\n\n```yaml\nexperimental_hoist_orphan_errors:\n  subgraphs:\n    my_subgraph:\n      enabled: true\n```\n\nAn example when targeting all subgraphs:\n\n```yaml\nexperimental_hoist_orphan_errors:\n  all:\n    enabled: true\n```\n\nAnd an example enabling for all subgraphs except one:\n\n```yaml\nexperimental_hoist_orphan_errors:\n  all:\n    enabled: true\n  subgraphs:\n    noisy_one:\n      enabled: false\n```\n\nUse this feature only if you know you have subgraphs that don't respond with the correct paths when making entity calls. If you're unsure, you probably don't need this.\n\nBy @aaronArinder in https://github.com/apollographql/router/pull/8998\n","publishedAt":"2026-03-31T18:58:25.000Z","url":"https://github.com/apollographql/router/releases/tag/v2.13.0","media":[]},{"id":"rel_IEOmi8uWSDLN4IaNHdxnN","version":"v2.13.0-rc.0","title":"v2.13.0-rc.0","summary":"","content":"","publishedAt":"2026-03-27T14:29:09.000Z","url":"https://github.com/apollographql/router/releases/tag/v2.13.0-rc.0","media":[]},{"id":"rel_fzJn36ak6-FE9NrlwikcS","version":"v2.12.1","title":"v2.12.1","summary":"## 🔒 Security\n\n> [!NOTE]\n> For more information on the impact of the fix in this release and how your deployment might be affected or remediated, see...","content":"## 🔒 Security\n\n> [!NOTE]\n> For more information on the impact of the fix in this release and how your deployment might be affected or remediated, see the corresponding GitHub Security Advisory (GHSA) linked below.  Updating to a patched Router version will resolve any vulnerabilities.\n\n### Reject GET requests with a non-`application/json` Content-Type header ([GHSA-hff2-gcpx-8f4p](https://github.com/apollographql/router/security/advisories/GHSA-hff2-gcpx-8f4p))\n\nThe router now rejects GraphQL `GET` requests that include a `Content-Type` header with a value other than `application/json` (with optional parameters such as `; charset=utf-8`). Any other value is rejected with a 415 status code.\n\n`GET` requests without a `Content-Type` header continue to be allowed (subject to the router's existing [CSRF prevention](/router/configuration/csrf) check), since `GET` requests have no body and therefore technically do not require this header.\n\nThis improvement makes the router's CSRF prevention more resistant to browsers that implement CORS in non-spec-compliant ways. Apollo is aware of one browser which as of March 2026 has a bug allowing an attacker to circumvent the router's CSRF prevention to carry out read-only XS-Search-style attacks. The browser vendor is in the process of patching this vulnerability; upgrading to this version of the router mitigates the vulnerability.\n\n**If your graph uses cookies (or HTTP Basic Auth) for authentication, Apollo encourages you to upgrade to this version.**\n\nThis is technically a backwards-incompatible change. Apollo is not aware of any GraphQL clients that provide non-empty `Content-Type` headers on `GET` requests with types other than `application/json`. If your use case requires such requests, please contact support, and we may add more configurability in a follow-up release.\n\n\nBy @glasser and @carodewig in [GHSA-hff2-gcpx-8f4p](https://github.com/apollographql/router/security/advisories/GHSA-hff2-gcpx-8f4p)\n","publishedAt":"2026-03-24T16:49:22.000Z","url":"https://github.com/apollographql/router/releases/tag/v2.12.1","media":[]},{"id":"rel_20xjW0fZ85P_KZ2vY9Hex","version":"v1.61.13","title":"v1.61.13","summary":"## 🔒 Security\n\n> [!NOTE]\n> For more information on the impact of the fix in this release and how your deployment might be affected or remediated, see...","content":"## 🔒 Security\n\n> [!NOTE]\n> For more information on the impact of the fix in this release and how your deployment might be affected or remediated, see the corresponding GitHub Security Advisory (GHSA) linked below.  Updating to a patched Router version will resolve any vulnerabilities.\n\n### Reject GET requests with a non-`application/json` Content-Type header ([GHSA-hff2-gcpx-8f4p](https://github.com/apollographql/router/security/advisories/GHSA-hff2-gcpx-8f4p))\n\nThe router now rejects GraphQL `GET` requests that include a `Content-Type` header with a value other than `application/json` (with optional parameters such as `; charset=utf-8`). Any other value is rejected with a 415 status code.\n\n`GET` requests without a `Content-Type` header continue to be allowed (subject to the router's existing [CSRF prevention](/router/configuration/csrf) check), since `GET` requests have no body and therefore technically do not require this header.\n\nThis improvement makes the router's CSRF prevention more resistant to browsers that implement CORS in non-spec-compliant ways. Apollo is aware of one browser which as of March 2026 has a bug allowing an attacker to circumvent the router's CSRF prevention to carry out read-only XS-Search-style attacks. The browser vendor is in the process of patching this vulnerability; upgrading to this version of the router mitigates the vulnerability.\n\n**If your graph uses cookies (or HTTP Basic Auth) for authentication, Apollo encourages you to upgrade to this version.**\n\nThis is technically a backwards-incompatible change. Apollo is not aware of any GraphQL clients that provide non-empty `Content-Type` headers on `GET` requests with types other than `application/json`. If your use case requires such requests, please contact support, and we may add more configurability in a follow-up release.\n\n\nBy @glasser and @carodewig in [GHSA-hff2-gcpx-8f4p](https://github.com/apollographql/router/security/advisories/GHSA-hff2-gcpx-8f4p)\n","publishedAt":"2026-03-24T15:28:15.000Z","url":"https://github.com/apollographql/router/releases/tag/v1.61.13","media":[]},{"id":"rel_ZkIU0SszHHESV_lgZo9oh","version":"v2.12.1-rc.0","title":"v2.12.1-rc.0","summary":"","content":"","publishedAt":"2026-03-24T15:22:15.000Z","url":"https://github.com/apollographql/router/releases/tag/v2.12.1-rc.0","media":[]},{"id":"rel_0MdTLS2hU62opLXmSAm-o","version":"v1.61.13-rc.0","title":"v1.61.13-rc.0","summary":"","content":"","publishedAt":"2026-03-24T14:54:11.000Z","url":"https://github.com/apollographql/router/releases/tag/v1.61.13-rc.0","media":[]},{"id":"rel_0tj7zVPyI7lzTiycW7SWj","version":"v2.10.2","title":"v2.10.2","summary":"## 🔒 Security\n\n> [!NOTE]\n> For more information on the impact of the fix in this release and how your deployment might be affected or remediated, see...","content":"## 🔒 Security\n\n> [!NOTE]\n> For more information on the impact of the fix in this release and how your deployment might be affected or remediated, see the corresponding GitHub Security Advisory (GHSA) linked below.  Updating to a patched Router version will resolve any vulnerabilities.\n\n### Reject GET requests with a non-`application/json` Content-Type header ([GHSA-hff2-gcpx-8f4p](https://github.com/apollographql/router/security/advisories/GHSA-hff2-gcpx-8f4p))\n\nThe router now rejects GraphQL `GET` requests that include a `Content-Type` header with a value other than `application/json` (with optional parameters such as `; charset=utf-8`). Any other value is rejected with a 415 status code.\n\n`GET` requests without a `Content-Type` header continue to be allowed (subject to the router's existing [CSRF prevention](/router/configuration/csrf) check), since `GET` requests have no body and therefore technically do not require this header.\n\nThis improvement makes the router's CSRF prevention more resistant to browsers that implement CORS in non-spec-compliant ways. Apollo is aware of one browser which as of March 2026 has a bug allowing an attacker to circumvent the router's CSRF prevention to carry out read-only XS-Search-style attacks. The browser vendor is in the process of patching this vulnerability; upgrading to this version of the router mitigates the vulnerability.\n\n**If your graph uses cookies (or HTTP Basic Auth) for authentication, Apollo encourages you to upgrade to this version.**\n\nThis is technically a backwards-incompatible change. Apollo is not aware of any GraphQL clients that provide non-empty `Content-Type` headers on `GET` requests with types other than `application/json`. If your use case requires such requests, please contact support, and we may add more configurability in a follow-up release.\n\n(This is a backport of a change from v2.12.1. This fix is not part of Router v2.11.0 through v2.12.0.)\n\nBy @glasser and @carodewig in [GHSA-hff2-gcpx-8f4p](https://github.com/apollographql/router/security/advisories/GHSA-hff2-gcpx-8f4p)\n","publishedAt":"2026-03-24T13:51:35.000Z","url":"https://github.com/apollographql/router/releases/tag/v2.10.2","media":[]},{"id":"rel_Wc5nIAElAoSPKeQGgfeno","version":"v2.10.2-rc.0","title":"v2.10.2-rc.0","summary":"","content":"","publishedAt":"2026-03-24T13:37:11.000Z","url":"https://github.com/apollographql/router/releases/tag/v2.10.2-rc.0","media":[]},{"id":"rel_EpWo_g1R1c5JyXb4ZhVbH","version":"v2.10.1","title":"v2.10.1","summary":"## 🐛 Fixes\n\n### Enforce feature restrictions for warning-state licenses\n\nThe router now enforces license restrictions even when a license is in a war...","content":"## 🐛 Fixes\n\n### Enforce feature restrictions for warning-state licenses\n\nThe router now enforces license restrictions even when a license is in a warning state. Previously, warning-state licenses could bypass enforcement for restricted features.\n\nIf your deployment uses restricted features, the router returns an error instead of continuing to run.\n\nBy @aaronArinder in https://github.com/apollographql/router/pull/8768\n\n## 🧪 Experimental\n\n### Add `experimental_hoist_orphan_errors` to control orphan error path assignment\n\nThe GraphQL specification requires that errors include a `path` pointing to the most specific field where the error occurred. When a subgraph returns entity errors without valid paths, the router's default behavior is its closest attempt at spec compliance: it assigns each error to every matching entity path in the response. This is the correct behavior when subgraphs respond correctly.\n\nHowever, when a subgraph returns a large number of entity errors without valid paths — for example, 2000 errors for 2000 expected entities — this causes a multiplicative explosion in the error array that can lead to significant memory pressure and out-of-memory kills. The root cause is the subgraph: a spec-compliant subgraph includes correct paths on its entity errors, and fixing the subgraph is the right long-term solution.\n\nThe new `experimental_hoist_orphan_errors` configuration provides an important mitigation while you work toward that fix. When enabled, the router assigns each orphaned error to the nearest non-array ancestor path instead of duplicating it across every entity. This trades spec-precise path assignment for substantially reduced error volume in the response — a conscious trade-off, not a strict improvement.\n\nTo target a specific subgraph:\n\n```yaml\nexperimental_hoist_orphan_errors:\n  subgraphs:\n    my_subgraph:\n      enabled: true\n```\n\nTo target all subgraphs:\n\n```yaml\nexperimental_hoist_orphan_errors:\n  all:\n    enabled: true\n```\n\nTo target all subgraphs except one:\n\n```yaml\nexperimental_hoist_orphan_errors:\n  all:\n    enabled: true\n  subgraphs:\n    noisy_one:\n      enabled: false\n```\n\nPer-subgraph settings override `all`. Note that this feature reduces the number of propagated errors but doesn't impose a hard cap — if your subgraph returns an extremely large number of errors, the router still processes all of them.\n\nYou'll likely know if you need this. Use it sparingly, and enable it only if you're affected and have been advised to do so. The behavior of this option is expected to change in a future release.\n\nFor full configuration reference and additional examples, see the [`experimental_hoist_orphan_errors` documentation](https://www.apollographql.com/docs/graphos/routing/configuration/yaml#experimental_hoist_orphan_errors).\n\nBy @aaronArinder in https://github.com/apollographql/router/pull/8998\n","publishedAt":"2026-03-11T15:49:31.000Z","url":"https://github.com/apollographql/router/releases/tag/v2.10.1","media":[]},{"id":"rel_SqqA5NUtfotqYELMdMaAJ","version":"v2.10.1-rc.2","title":"v2.10.1-rc.2","summary":"","content":"","publishedAt":"2026-03-11T10:14:17.000Z","url":"https://github.com/apollographql/router/releases/tag/v2.10.1-rc.2","media":[]},{"id":"rel_YgJhq8Oew1sgLP7unMMfP","version":"v2.10.1-rc.1","title":"v2.10.1-rc.1","summary":"","content":"","publishedAt":"2026-03-10T20:59:15.000Z","url":"https://github.com/apollographql/router/releases/tag/v2.10.1-rc.1","media":[]},{"id":"rel_qT1ieRnE9NCsdlhLNflfI","version":"v2.12.0","title":"v2.12.0","summary":"## 🚀 Features\r\n\r\n### Support Unix domain socket (UDS) communication for coprocessors ([Issue #5739](https://github.com/apollographql/router/issues/57...","content":"## 🚀 Features\r\n\r\n### Support Unix domain socket (UDS) communication for coprocessors ([Issue #5739](https://github.com/apollographql/router/issues/5739))\r\n\r\nMany coprocessor deployments run side-by-side with the router, typically on the same host (for example, within the same Kubernetes pod).\r\n\r\nThis change brings coprocessor communication to parity with subgraphs by adding Unix domain socket (UDS) support. When the router and coprocessor are co-located, communicating over a Unix domain socket bypasses the full TCP/IP network stack and uses shared host memory instead, which can meaningfully reduce latency compared to HTTP.\r\n\r\nBy @theJC in https://github.com/apollographql/router/pull/8348\r\n\r\n### Add `redact_query_validation_errors` supergraph config option ([PR #8888](https://github.com/apollographql/router/pull/8888))\r\n\r\nThe new `redact_query_validation_errors` option in the `supergraph` configuration section replaces all query validation errors with a single generic error:\r\n\r\n```json\r\n{\r\n  \"message\": \"invalid query\",\r\n  \"extensions\": {\r\n    \"code\": \"UNKNOWN_ERROR\"\r\n  }\r\n}\r\n```\r\n\r\nBy @phryneas in https://github.com/apollographql/router/pull/8888\r\n\r\n### Support multiple `@listSize` directives on the same field ([PR #8872](https://github.com/apollographql/router/pull/8872))\r\n\r\n> [!WARNING]\r\n>\r\n> Multiple `@listSize` directives on a field only take effect after Federation supports repeatable `@listSize` in the supergraph schema. Until then, composition continues to expose at most one directive per field. This change makes the router ready for that Federation release.\r\n\r\nThe router now supports multiple `@listSize` directives on a single field, enabling more flexible cost estimation when directives from different subgraphs are combined during federation composition.\r\n\r\n- The router processes all `@listSize` directives on a field (stored as `Vec<ListSizeDirective>` instead of `Option<ListSizeDirective>`).\r\n- When multiple directives specify `assumedSize` values, the router uses the maximum value for cost calculation.\r\n- Existing schemas with single directives continue to work exactly as before.\r\n\r\nThis change prepares the router for federation's upcoming support for repeatable `@listSize` directives, and maintains full compatibility with current non-repeatable directive schemas.\r\n\r\nBy @cmorris in https://github.com/apollographql/router/pull/8872\r\n\r\n### Add parser recursion and lexical token metrics ([PR #8845](https://github.com/apollographql/router/pull/8845))\r\n\r\nThe router now emits two new metrics: `apollo.router.operations.recursion` for the recursion level reached, and `apollo.router.operations.lexical_tokens` for the number of lexical tokens in a query.\r\n\r\nBy @jhrldev in https://github.com/apollographql/router/pull/8845\r\n\r\n### Support subgraph-level demand control ([PR #8829](https://github.com/apollographql/router/pull/8829))\r\n\r\nSubgraph-level demand control lets you enforce per-subgraph query cost limits in the 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.\r\n\r\nWhen a subgraph-specific cost limit is exceeded, the router:\r\n\r\n- Still runs the rest of the operation, including other subgraphs whose cost is within limits.\r\n- 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.\r\n\r\nPer-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.\r\n\r\n#### Configuration\r\n\r\n```yaml\r\ndemand_control:\r\n  enabled: true\r\n  mode: enforce\r\n  strategy:\r\n    static_estimated:\r\n      max: 10\r\n      list_size: 10\r\n      actual_cost_mode: by_subgraph\r\n      subgraphs: # everything from here down is new (all fields optional)\r\n        all:\r\n          max: 8\r\n          list_size: 10\r\n        subgraphs:\r\n          products:\r\n            max: 6\r\n            # list_size omitted, 10 implied because of all.list_size\r\n          reviews:\r\n            list_size: 50\r\n            # max omitted, 8 implied because of all.max\r\n```\r\n\r\n#### Example\r\n\r\nConsider a `topProducts` query that fetches a list of products from a products subgraph and then performs an entity lookup for each product in a reviews subgraph. Assume the products cost is 10 and the reviews cost is 5, leading to a total estimated cost of 15 (10 + 5).\r\n\r\nPreviously, you could only restrict that query via `demand_control.static_estimated.max`:\r\n\r\n- If you set it to 15 or higher, the query executes.\r\n- If you set it below 15, the query is rejected.\r\n\r\nSubgraph-level demand control enables much more granular control. In addition to `demand_control.static_estimated.max`, which operates as before, you can also set per-subgraph limits.\r\n\r\nFor example, if you set `max = 20` and `reviews.max = 2`, the query passes the aggregate check (15 < 20) and executes on the products subgraph (no limit specified), but doesn't execute against the reviews subgraph (5 > 2). The result is composed as if the reviews subgraph had returned null.\r\n\r\nBy @carodewig in https://github.com/apollographql/router/pull/8829\r\n\r\n### Improve `@listSize` directive parsing and nested path support ([PR #8893](https://github.com/apollographql/router/pull/8893))\r\n\r\nDemand control cost calculation now supports:\r\n\r\n- Array-style parsing for `@listSize` sizing (for example, list arguments)\r\n- Nested input paths when resolving list size from query arguments\r\n- Nested field paths in the `sizedFields` argument on `@listSize` for more accurate cost estimation\r\n\r\nThese changes are backward compatible with existing schemas and directives.\r\n\r\nBy @cmorris in https://github.com/apollographql/router/pull/8893\r\n\r\n### Add coprocessor hooks for connector request and response stages ([PR #8869](https://github.com/apollographql/router/pull/8869))\r\n\r\nYou can now configure a coprocessor hook for the `ConnectorRequest` and `ConnectorResponse` stages of the router lifecycle.\r\n\r\n```yaml\r\ncoprocessor:\r\n  url: http://localhost:3007\r\n  connector:\r\n    all:\r\n      request:\r\n        uri: true\r\n        headers: true\r\n        body: true\r\n        context: all\r\n        service_name: true\r\n      response:\r\n        headers: true\r\n        body: true\r\n        context: all\r\n        service_name: true\r\n```\r\n\r\nBy @andrewmcgivery in https://github.com/apollographql/router/pull/8869\r\n\r\n## 🐛 Fixes\r\n\r\n### Pass variables to introspection queries ([PR #8816](https://github.com/apollographql/router/pull/8816))\r\n\r\nIntrospection queries now receive variables, enabling `@include` and `@skip` directives during introspection.\r\n\r\nBy @jephuff in https://github.com/apollographql/router/pull/8816\r\n\r\n### Log warning instead of returning error for non-UTF-8 headers in `externalize_header_map` ([PR #8828](https://github.com/apollographql/router/pull/8828))\r\n\r\n- The router now emits a warning log with the name of the header instead of returning an error.\r\n- The remaining valid headers are returned, which is more consistent with the router's default behavior when a coprocessor isn't used.\r\n\r\nBy @rohan-b99 in https://github.com/apollographql/router/pull/8828\r\n\r\n### Place `http_client` span attributes on the `http_request` span ([PR #8798](https://github.com/apollographql/router/pull/8798))\r\n\r\nAttributes configured under `telemetry.instrumentation.spans.http_client` are now added to the `http_request` span instead of `subgraph_request`.\r\n\r\nGiven this config:\r\n\r\n```yaml\r\ntelemetry:\r\n  instrumentation:\r\n    spans:\r\n      http_client:\r\n        attributes:\r\n          http.request.header.content-type:\r\n            request_header: \"content-type\"\r\n          http.response.header.content-type:\r\n            response_header: \"content-type\"\r\n```\r\n\r\nBoth attributes are now placed on the `http_request` span.\r\n\r\nBy @rohan-b99 in https://github.com/apollographql/router/pull/8798\r\n\r\n### Validate `ObjectValue` variable fields against input type definitions ([PR #8821](https://github.com/apollographql/router/pull/8821) and [PR #8884](https://github.com/apollographql/router/pull/8884))\r\n\r\nThe router now validates individual fields of input object variables against their type definitions. Previously, variable validation checked that the variable itself was present but didn't validate the fields within the object.\r\n\r\nExample:\r\n```graphql\r\n## schema ##\r\ninput MessageInput {\r\n    content: String\r\n    author: String\r\n}\r\ntype Receipt {\r\n    id: ID!\r\n}\r\ntype Query{\r\n    send(message: MessageInput): Receipt\r\n}\r\n\r\n## query ##\r\nquery(: MessageInput) {\r\n    send(message: ) {\r\n        id\r\n    }\r\n}\r\n\r\n## input variables ##\r\n{\"msg\":\r\n    {\r\n    \"content\": \"Hello\",\r\n    \"author\": \"Me\",\r\n    \"unknownField\": \"unknown\",\r\n    }\r\n}\r\n```\r\nThis request previously passed validation because the variable `msg` was present in the input, but the fields of `msg` weren't validated against the `MessageInput` type.\r\n\r\n> [!WARNING]\r\n> To opt out of this behavior, set the `supergraph.strict_variable_validation` config option to `measure`.\r\n\r\nEnabled:\r\n```yaml\r\nsupergraph:\r\n  strict_variable_validation: enforce\r\n```\r\n\r\nDisabled:\r\n```yaml\r\nsupergraph:\r\n  strict_variable_validation: measure\r\n```\r\n\r\nBy @conwuegb in https://github.com/apollographql/router/pull/8821 and https://github.com/apollographql/router/pull/8884\r\n\r\n### Increase internal Redis timeout from 5s to 10s ([PR #8863](https://github.com/apollographql/router/pull/8863))\r\n\r\nBecause mTLS handshakes can be slow in some environments, the internal Redis timeout is now 10s (previously 5s). The connection \"unresponsive\" threshold is also increased from 5s to 10s.\r\n\r\nBy @aaronarinder in https://github.com/apollographql/router/pull/8863\r\n\r\n### Enforce and log operation limits for cached query plans ([PR #8810](https://github.com/apollographql/router/pull/8810))\r\n\r\nThe router now logs the operation-limits warning for cached query plans as well, ensuring the query text is included whenever limits are exceeded. This also fixes a case where a cached plan could bypass enforcement after changing `warn_only` from `true` to `false` during a hot reload.\r\n\r\nBy @rohan-b99 in https://github.com/apollographql/router/pull/8810\r\n\r\n### Prevent duplicate `content-type` headers in connectors ([PR #8867](https://github.com/apollographql/router/pull/8867))\r\n\r\nWhen you override the `content-type` header in a connector `@source` directive, the router no longer appends the default value. The custom header value now properly replaces the default.\r\n\r\nFor example:\r\n\r\n```graphql\r\n@source(\r\n    name: \"datasetInsightsAPI\"\r\n    http: {\r\n        headers: [\r\n            { name: \"Content-Type\", value: \"application/vnd.iaas.v1+json\" },\r\n        ]\r\n    }\r\n)\r\n```\r\n\r\nPreviously resulted in:\r\n\r\n```http\r\ncontent-type: application/json, application/vnd.iaas.v1+json\r\n```\r\n\r\nNow correctly results in:\r\n\r\n```http\r\ncontent-type: application/vnd.iaas.v1+json\r\n```\r\n\r\nBy @andrewmcgivery in https://github.com/apollographql/router/pull/8867\r\n\r\n### Prevent duplicate tags in router spans added by dynamic attributes ([PR #8865](https://github.com/apollographql/router/pull/8865))\r\n\r\nWhen dynamic attributes are added via `SpanDynAttribute::insert`, `SpanDynAttribute::extend`, `LogAttributes::insert`, `LogAttributes::extend`, `EventAttributes::insert`, or `EventAttributes::extend` and the key already exists, the router now replaces the existing value instead of creating duplicate attributes.\r\n\r\nBy @rohan-b99 in https://github.com/apollographql/router/pull/8865\r\n\r\n### Compute actual demand control costs across all subgraph fetches ([PR #8827](https://github.com/apollographql/router/pull/8827))\r\n\r\nThe demand control feature estimates query costs by summing together the cost of each subgraph operation, capturing any intermediate work that must be completed to return a complete response.\r\n\r\nPreviously, the actual query cost computation only considered the final response shape and didn't include any of the intermediate work in its total.\r\n\r\nThe router now computes the actual query cost as the sum of all subgraph response costs. This more accurately reflects the work done per operation and enables a more meaningful comparison between actual and estimated costs.\r\n\r\nTo disable the new actual cost computation behavior, set the router configuration option `demand_control.strategy.static_estimated.actual_cost_mode` to `response_shape`:\r\n\r\n```yaml\r\ndemand_control:\r\n  enabled: true\r\n  mode: enforce\r\n  strategy:\r\n    static_estimated:\r\n      max: 10\r\n      list_size: 10\r\n      actual_cost_mode: by_subgraph # the default value\r\n      # actual_cost_mode: response_shape # revert to prior actual cost computation mode\r\n```\r\n\r\nBy @carodewig in https://github.com/apollographql/router/pull/8827\r\n\r\n## 📚 Documentation\r\n\r\n### Correct response caching FAQ for schema updates and multi-root-field caching ([PR #8794](https://github.com/apollographql/router/pull/8794))\r\n\r\nUpdated the response caching FAQ to accurately describe caching behavior:\r\n\r\n- Clarify that schema updates generate new cache keys, so old entries don't receive cache hits (effectively expired from your perspective) instead of implying stale data might be served.\r\n- Correct the multi-root-field caching explanation to state that the router caches the entire subgraph response as a single unit, not separately per root field.\r\n- Add clarification that the configured TTL is a fallback when subgraph responses don't include `Cache-Control: max-age` headers.\r\n- Change example TTL from `300s` to `5m` for better readability.\r\n\r\nBy @the-gigi-apollo in https://github.com/apollographql/router/pull/8794\r\n","publishedAt":"2026-02-24T15:31:03.000Z","url":"https://github.com/apollographql/router/releases/tag/v2.12.0","media":[]},{"id":"rel_RADYOEgvBMWcfCKlmjVMZ","version":"v2.12.0-rc.1","title":"v2.12.0-rc.1","summary":"","content":"","publishedAt":"2026-02-18T16:52:33.000Z","url":"https://github.com/apollographql/router/releases/tag/v2.12.0-rc.1","media":[]},{"id":"rel_SOFFB1a83B4_EIJNQUw5f","version":"v2.12.0-rc.0","title":"v2.12.0-rc.0","summary":"","content":"","publishedAt":"2026-02-18T13:23:25.000Z","url":"https://github.com/apollographql/router/releases/tag/v2.12.0-rc.0","media":[]},{"id":"rel_4EnS0FPTyjJqRXhW5BNPP","version":"v2.12.0-alpha.0","title":"v2.12.0-alpha.0","summary":"","content":"","publishedAt":"2026-02-18T11:26:03.000Z","url":"https://github.com/apollographql/router/releases/tag/v2.12.0-alpha.0","media":[]},{"id":"rel_4shLlWQcXn1wUi3U8IpmL","version":"v2.11.0","title":"v2.11.0","summary":"## 🚀 Features\r\n\r\n### Support client awareness metadata via HTTP headers ([PR #8503](https://github.com/apollographql/router/pull/8503))\r\n\r\nClients ca...","content":"## 🚀 Features\r\n\r\n### Support client awareness metadata via HTTP headers ([PR #8503](https://github.com/apollographql/router/pull/8503))\r\n\r\nClients can now send library name and version metadata for client awareness and enhanced client awareness using HTTP headers. This provides a consistent transport mechanism instead of splitting values between headers and `request.extensions`.\r\n\r\nBy @calvincestari in https://github.com/apollographql/router/pull/8503\r\n\r\n### Reload OCI artifacts when a tag reference changes ([PR #8805](https://github.com/apollographql/router/pull/8805))\r\n\r\nYou can now configure tag-based OCI references in the router. When you use a tag reference such as `artifacts.apollographql.com/my-org/my-graph:prod`, the router polls and reloads when that tag points to a new artifact.\r\n\r\nThis also applies to automatically generated variant tags and custom tags.\r\n\r\nBy @graytonio in https://github.com/apollographql/router/pull/8805\r\n\r\n### Add memory limit option for cooperative cancellation ([PR #8808](https://github.com/apollographql/router/pull/8808))\r\n\r\nThe router now supports a `memory_limit` option on `experimental_cooperative_cancellation` to cap memory allocations during query planning. When the memory limit is exceeded, the router:\r\n\r\n- In `enforce` mode, cancels query planning and returns an error to the client.\r\n- In `measure` mode, records the cancellation outcome in metrics and allows query planning to complete.\r\n\r\nThe memory limit works alongside the existing `timeout` option. Whichever limit is reached first triggers cancellation.\r\n\r\nThis feature is only available on Unix platforms when the `global-allocator` feature is enabled and `dhat-heap` is not enabled.\r\n\r\nExample configuration:\r\n\r\n```yaml\r\nsupergraph:\r\n  query_planning:\r\n    experimental_cooperative_cancellation:\r\n      enabled: true\r\n      mode: enforce  # or \"measure\" to only record metrics\r\n      memory_limit: 50mb  # Supports formats like \"50mb\", \"1gb\", \"1024kb\", etc.\r\n      timeout: 5s  # Optional: can be combined with memory_limit\r\n```\r\n\r\nBy @rohan-b99 in https://github.com/apollographql/router/pull/8808\r\n\r\n### Add memory tracking metrics for requests ([PR #8717](https://github.com/apollographql/router/pull/8717))\r\n\r\nThe router now emits two histogram metrics to track memory allocation activity during request processing:\r\n\r\n- `apollo.router.request.memory`: Memory activity across the full request lifecycle (including parsing, validation, query planning, and plugins)\r\n- `apollo.router.query_planner.memory`: Memory activity for query planning work in the compute job thread pool\r\n\r\nEach metric includes:\r\n\r\n- `allocation.type`: `allocated`, `deallocated`, `zeroed`, or `reallocated`\r\n- `context`: The tracking context name (for example, `router.request` or `query_planning`)\r\n\r\nThis feature is only available on Unix platforms when the `global-allocator` feature is enabled and `dhat-heap` is not enabled.\r\n\r\nBy @rohan-b99 in https://github.com/apollographql/router/pull/8717\r\n\r\n## 🐛 Fixes\r\n\r\n### Support nullable `@key` fields in response caching ([PR #8767](https://github.com/apollographql/router/pull/8767))\r\n\r\nResponse caching can now use nullable `@key` fields. Previously, the response caching feature rejected nullable `@key` fields, which prevented caching in schemas that use them.\r\n\r\nWhen you cache data keyed by nullable fields, keep your cache keys simple and avoid ambiguous `null` values.\r\n\r\nBy @aaronArinder in https://github.com/apollographql/router/pull/8767\r\n\r\n### Return `429` instead of `503` when enforcing a rate limit ([PR #8765](https://github.com/apollographql/router/pull/8765))\r\n\r\nIn v2.0.0, the router changed the rate-limiting error from `429` (`TOO_MANY_REQUESTS`) to `503` (`SERVICE_UNAVAILABLE`). This change restores `429` to align with the [router error documentation](https://www.apollographql.com/docs/graphos/routing/errors#429).\r\n\r\nBy @carodewig in https://github.com/apollographql/router/pull/8765\r\n\r\n### Add status code and error type attributes to `http_request` spans ([PR #8775](https://github.com/apollographql/router/pull/8775))\r\n\r\nThe router now always adds the `http.response.status_code` attribute to `http_request` spans (for example, for `router -> subgraph` requests). The router also conditionally adds `error.type` for non-success status codes.\r\n\r\nBy @rohan-b99 in https://github.com/apollographql/router/pull/8775\r\n\r\n### Report response cache invalidation failures as errors ([PR #8813](https://github.com/apollographql/router/pull/8813))\r\n\r\nThe router now returns an error when response cache invalidation fails. Previously, an invalidation attempt could fail without being surfaced as an error.\r\n\r\nAfter you upgrade, you might see an increase in the `apollo.router.operations.response_cache.invalidation.error` metric.\r\n\r\nBy @bnjjj in https://github.com/apollographql/router/pull/8813\r\n\r\n### Reuse response cache Redis connections for identical subgraph configuration ([PR #8764](https://github.com/apollographql/router/pull/8764))\r\n\r\nThe response cache now reuses Redis connection pools when subgraph-level configuration resolves to the same Redis configuration as the global `all` setting. Previously, the router could create redundant Redis connections even when the effective configuration was identical.\r\n\r\nImpact: If you configure response caching at both the global and subgraph levels, you should see fewer Redis connections and lower connection overhead.\r\n\r\nBy @bnjjj in https://github.com/apollographql/router/pull/8764\r\n\r\n### Prevent TLS connections from hanging when a handshake stalls ([PR #8779](https://github.com/apollographql/router/pull/8779))\r\n\r\nThe router listener loop no longer blocks while waiting for a TLS handshake to complete. Use `server.http.tls_handshake_timeout` to control how long the router waits before terminating a connection (default: `10s`).\r\n\r\nBy @rohan-b99 in https://github.com/apollographql/router/pull/8779\r\n\r\n### Emit cardinality overflow metrics for more OpenTelemetry error formats ([PR #8740](https://github.com/apollographql/router/pull/8740))\r\n\r\nThe router now emits the `apollo.router.telemetry.metrics.cardinality_overflow` metric for additional OpenTelemetry cardinality overflow error formats.\r\n\r\nBy @bonnici in https://github.com/apollographql/router/pull/8740\r\n\r\n### Propagate trace context on WebSocket upgrade requests ([PR #8739](https://github.com/apollographql/router/pull/8739))\r\n\r\nThe router now injects trace propagation headers into the initial HTTP upgrade request when it opens WebSocket connections to subgraphs. This preserves distributed trace continuity between the router and subgraph services.\r\n\r\nTrace propagation happens during the HTTP handshake only. After the WebSocket connection is established, headers cannot be added to individual messages.\r\n\r\nBy @theJC in https://github.com/apollographql/router/pull/8739\r\n\r\n### Stop query planning compute jobs when the parent task is canceled ([PR #8741](https://github.com/apollographql/router/pull/8741))\r\n\r\nQuery planning compute jobs now stop when cooperative cancellation cancels the parent task.\r\n\r\nBy @rohan-b99 in https://github.com/apollographql/router/pull/8741\r\n\r\n### Reject invalidation requests with unknown fields ([PR #8752](https://github.com/apollographql/router/pull/8752))\r\n\r\nThe response cache invalidation endpoint now rejects request payloads that include unknown fields. When unknown fields are present, the router returns HTTP `400` (Bad Request).\r\n\r\nBy @bnjjj in https://github.com/apollographql/router/pull/8752\r\n\r\n### Restore plugin access to `SubscriptionTaskParams` in `execution::Request` builders ([PR #8771](https://github.com/apollographql/router/pull/8771))\r\n\r\nPlugins and other external crates can use `SubscriptionTaskParams` with `execution::Request` builders again. This restores compatibility for plugin unit tests that construct subscription requests.\r\n\r\nBy @aaronArinder in https://github.com/apollographql/router/pull/8771\r\n\r\n### Support JWT tokens with multiple audiences ([PR #8780](https://github.com/apollographql/router/pull/8780))\r\n\r\nWhen `issuers` or `audiences` is included in the router's JWK configuration, the router will check each request's JWT for `iss` or `aud` and reject requests with mismatches.\r\n\r\nExpected behavior:\r\n- If present, the [`iss`](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.1) claim must be specified as a string.\r\n  - ✅  The JWK's `issuers` is empty.\r\n  - ✅  The `iss` is a string and is present in the JWK's `issuers`.\r\n  - ✅  The `iss` is null.\r\n  - ❌  The `iss` is a string but is not present in the JWK's `issuers`.\r\n  - ❌  The `iss` is not a string or null.\r\n- If present, the [`aud`](https://datatracker.ietf.org/doc/html/rfc7519#section-4.1.3) claim can be specified as either a string or an array of strings.\r\n  - ✅  The JWK's `audiences` is empty.\r\n  - ✅  The `aud` is a string and is present in the JWK's `audiences`.\r\n  - ✅  The `aud` is an array of strings and at least one of those strings is present in the JWK's `audiences`.\r\n  - ❌  The `aud` is not a string or array of strings (i.e., null).\r\n\r\nBehavior prior to this change:\r\n- If the `iss` was not null or a string, it was permitted (regardless of its value).\r\n- If the `aud` was an array, it was rejected (regardless of its value).\r\n\r\nBy @carodewig in https://github.com/apollographql/router/pull/8780\r\n\r\n### Enforce feature restrictions for warning-state licenses ([PR #8768](https://github.com/apollographql/router/pull/8768))\r\n\r\nThe router now enforces license restrictions even when a license is in a warning state. Previously, warning-state licenses could bypass enforcement for restricted features.\r\n\r\nIf your deployment uses restricted features, the router returns an error instead of continuing to run.\r\n\r\nBy @aaronArinder in https://github.com/apollographql/router/pull/8768\r\n\r\n## 🛠 Maintenance\r\n\r\n### Warn at startup when `OTEL_EXPORTER_OTLP_ENDPOINT` is set ([PR #8729](https://github.com/apollographql/router/pull/8729))\r\n\r\nThe router now displays a warning at startup if the `OTEL_EXPORTER_OTLP_ENDPOINT` environment variable is set. This variable takes precedence over default configurations and can override trace export to Apollo Studio, so the warning helps you identify when telemetry data might not be sent where expected.\r\n\r\nBy @apollo-mateuswgoettems in https://github.com/apollographql/router/pull/8729\r\n\r\n### Increase Redis 'unresponsive' check frequency ([PR #8763](https://github.com/apollographql/router/pull/8763))\r\n\r\nPerform the 'unresponsive' check every two seconds. This aligns with the Redis client's guideline that the check interval should be less than half the timeout value.\r\n\r\nBy @carodewig in https://github.com/apollographql/router/pull/8763\r\n\r\n## 📚 Documentation\r\n\r\n### Fix subscription licensing discrepancy in documentation ([PR #8726](https://github.com/apollographql/router/pull/8726))\r\n\r\nCorrected the subscription support documentation to reflect that subscriptions are available on all GraphOS plans (Free, Developer, Standard, and Enterprise) with self-hosted routers.\r\n\r\nThe documentation previously stated that subscription support was an Enterprise-only feature for self-hosted routers, which was incorrect. Subscriptions are a licensed feature available to all GraphOS plans when the router is connected to GraphOS with an API key and graph ref.\r\n\r\nUpdated both the configuration and overview pages to remove the misleading Enterprise-only requirement and clarify the actual requirements.\r\n\r\nBy @the-gigi-apollo in https://github.com/apollographql/router/pull/8726\r\n\r\n### Clarify traffic shaping compression headers in documentation ([PR #8773](https://github.com/apollographql/router/pull/8773))\r\n\r\nThe traffic shaping documentation now clearly explains how the router handles HTTP compression headers for subgraph requests. It clarifies that `content-encoding` is set when compression is configured via `traffic_shaping`, while `accept-encoding` is automatically set on all subgraph requests to indicate the router can accept compressed responses (`gzip`, `br`, or `deflate`). The documentation also notes that these headers are added after requests are added to the debug stack, so they won't appear in the Connectors Debugger.\r\n\r\nBy @the-gigi-apollo in https://github.com/apollographql/router/pull/8773\r\n\r\n### Document default histogram buckets and their relationship to timeout settings ([PR #8783](https://github.com/apollographql/router/pull/8783))\r\n\r\nThe documentation now explains how histogram bucket configuration affects timeout monitoring in Prometheus and other metrics exporters.\r\n\r\nThe documentation now includes:\r\n\r\n- Default bucket values: The router's default histogram buckets (`0.001` to `10.0` seconds)\r\n- Timeout behavior: Histogram metrics cap values at the highest bucket boundary, which can make timeouts appear ignored if they exceed ten seconds\r\n- Customization guidance: Configure custom buckets via `telemetry.exporters.metrics.common.buckets` to match your timeout settings\r\n\r\nThis update helps users understand why their timeout metrics may not behave as expected and provides clear guidance on customizing buckets for applications with longer timeout configurations.\r\n\r\nBy @the-gigi-apollo in https://github.com/apollographql/router/pull/8783\r\n","publishedAt":"2026-01-27T15:04:59.000Z","url":"https://github.com/apollographql/router/releases/tag/v2.11.0","media":[]},{"id":"rel_VV7kQE89TraS1_8GTdBwj","version":"v2.11.0-rc.0","title":"v2.11.0-rc.0","summary":"","content":"","publishedAt":"2026-01-22T16:55:36.000Z","url":"https://github.com/apollographql/router/releases/tag/v2.11.0-rc.0","media":[]},{"id":"rel_QT7Tx7ukMyiPxgtpGQN19","version":"v2.11.0-abstract.1","title":"v2.11.0-abstract.1","summary":"","content":"","publishedAt":"2025-12-18T20:08:01.000Z","url":"https://github.com/apollographql/router/releases/tag/v2.11.0-abstract.1","media":[]}],"pagination":{"page":1,"pageSize":20,"totalPages":5,"totalItems":100},"summaries":{"rolling":null,"monthly":[]}}