Releases: graphql-hive/router
Release list
apollo-router-hive-fork 3.1.1 (2026-08-16)
Fixes
Stop cancellation from interrupting an active usage flush
The usage agent now observes cancellation while waiting for the next flush interval instead of checking only after the full interval has elapsed. Cancellation remains pending while an active flush completes, preventing a drained report batch from being lost when its send future is interrupted.
hive-router 0.1.0 (2026-08-13)
Breaking Changes
Fix missing demand control metrics names
Previously added metrics names were missing the hive.router.demand_control. prefix. This has been fixed in this change.
Here's a list of the metrics that have been fixed:
cost.estimated->hive.router.demand_control.cost.estimatedcost.actual->hive.router.demand_control.cost.actualcost.delta->hive.router.demand_control.cost.delta
Fixes
Allow async fn in the on_http_request plugin hook
RouterPlugin::on_http_request now returns OnHttpRequestHookFuture<'req> instead of OnHttpRequestHookResult<'req> directly, so plugins can await inside - for example calling an upstream auth or feature-flag service - before the rest of the request pipeline runs.
The hook still runs on the same worker thread it started on and is never moved across threads, so the returned future does not need to be Send.
Update any plugin that overrides on_http_request to return a boxed future:
// Before
fn on_http_request<'req>(
&self,
payload: OnHttpRequestHookPayload<'req>,
) -> OnHttpRequestHookResult<'req> {
self.record_request(&payload);
payload.proceed()
}
// After
fn on_http_request<'req>(
&'req self,
payload: OnHttpRequestHookPayload<'req>,
) -> OnHttpRequestHookFuture<'req> {
Box::pin(async move {
self.record_request(&payload);
payload.proceed()
})
}If the body reads self inside the async move block, &self needs to become &'req self - the future now holds that borrow for its own lifetime 'req, so the borrow has to be able to live at least that long.
Plugins that don't override on_http_request are unaffected.
See plugin_examples/async_http_fetch for an example that awaits an upstream HTTP call before proceeding.
hive-router-plan-executor 8.0.0 (2026-08-13)
Breaking Changes
Allow async fn in the on_http_request plugin hook
RouterPlugin::on_http_request now returns OnHttpRequestHookFuture<'req> instead of OnHttpRequestHookResult<'req> directly, so plugins can await inside - for example calling an upstream auth or feature-flag service - before the rest of the request pipeline runs.
The hook still runs on the same worker thread it started on and is never moved across threads, so the returned future does not need to be Send.
Update any plugin that overrides on_http_request to return a boxed future:
// Before
fn on_http_request<'req>(
&self,
payload: OnHttpRequestHookPayload<'req>,
) -> OnHttpRequestHookResult<'req> {
self.record_request(&payload);
payload.proceed()
}
// After
fn on_http_request<'req>(
&'req self,
payload: OnHttpRequestHookPayload<'req>,
) -> OnHttpRequestHookFuture<'req> {
Box::pin(async move {
self.record_request(&payload);
payload.proceed()
})
}If the body reads self inside the async move block, &self needs to become &'req self - the future now holds that borrow for its own lifetime 'req, so the borrow has to be able to live at least that long.
Plugins that don't override on_http_request are unaffected.
See plugin_examples/async_http_fetch for an example that awaits an upstream HTTP call before proceeding.
hive-router-internal 0.1.0 (2026-08-13)
Breaking Changes
Fix missing demand control metrics names
Previously added metrics names were missing the hive.router.demand_control. prefix. This has been fixed in this change.
Here's a list of the metrics that have been fixed:
cost.estimated->hive.router.demand_control.cost.estimatedcost.actual->hive.router.demand_control.cost.actualcost.delta->hive.router.demand_control.cost.delta
hive-router 0.0.89 (2026-08-12)
Features
Multiplex and reuse WebSocket subgraph connections
The router can now multiplex GraphQL operations over shared graphql-transport-ws subgraph connections.
Subscriptions with the same subgraph and inbound connection identity reuse one initialized connection instead of opening one WebSocket per operation. Different operations retain independent streams while sharing the physical connection.
Queries and mutations can also reuse a connection opened by a subscription:
subscriptions:
enabled: true
websocket:
subgraphs:
reviews:
path: /reviews/ws
traffic_shaping:
all:
websocket:
reuse_connections: true
execute_mode: reuse_existingWith this configuration:
- A subscription initializes the pooled
reviewsconnection. - Matching subscriptions multiplex over it.
- Matching queries and mutations use it while it remains initialized.
- A query or mutation uses HTTP when the connection is missing, expired, or still initializing.
Use WebSocket for every operation by selecting websocket mode:
traffic_shaping:
all:
websocket:
reuse_connections: true
execute_mode: websocketThe first operation initializes the connection, concurrent operations join that initialization, and later matching operations reuse the initialized connection.
Once an operation selects WebSocket, transport failures and timeouts are returned to the client without retrying over HTTP. This prevents a mutation that may have reached the subgraph from being executed twice.
Idle pooled connections close after the effective pool_idle_timeout. Active operations keep the connection open, and dropping one operation cancels only that operation without closing the shared connection.
The router also exposes WebSocket pool telemetry for active connections and operations, initialization success and failure, initialization waiters, reuse lookup hits and misses, and connection closure reasons. These metrics help measure reuse hit rate, multiplexing, connection churn, handshake failures, and per-subgraph pool usage.
Fixes
Add WebSocket connection reuse and execution mode configuration
WebSocket-enabled subgraphs can now configure connection reuse and choose how queries and mutations are transported.
Configure defaults for all subgraphs under traffic_shaping.all.websocket:
subscriptions:
enabled: true
websocket:
subgraphs:
reviews:
path: /reviews/ws
traffic_shaping:
all:
pool_idle_timeout: 50s # default
websocket:
reuse_connections: true
execute_mode: reuse_existingreuse_connections defaults to true:
truemultiplexes matching operations over initialized pooled WebSocket connectionsfalseopens a dedicated connection for each WebSocket operation
execute_mode defaults to http and supports:
http: queries and mutations always use HTTPreuse_existing: queries and mutations use an initialized matching WebSocket when available, otherwise they immediately use HTTPwebsocket: queries and mutations use WebSocket, creating or joining a pooled connection when reuse is enabled
Settings can be overridden per subgraph. Omitted WebSocket fields inherit the global value:
traffic_shaping:
all:
pool_idle_timeout: 50s # default
websocket:
reuse_connections: true
execute_mode: reuse_existing
subgraphs:
payments:
pool_idle_timeout: 5s
websocket:
reuse_connections: false
execute_mode: websocketIn this example, other WebSocket-enabled subgraphs opportunistically reuse initialized connections. payments sends each operation over a dedicated WebSocket.
Pooled WebSockets use the effective pool_idle_timeout. A per-subgraph value overrides traffic_shaping.all.pool_idle_timeout for both HTTP and WebSocket pools. Active WebSocket operations do not expire.
Connection matching uses the inbound headers selected by traffic_shaping.router.dedupe.headers, even when router request deduplication is disabled. Include every header that can affect connection-scoped authentication, authorization, cookies, or tenant identity:
traffic_shaping:
router:
dedupe:
headers:
include: [authorization, cookie, x-tenant]Improve variable coercion error messages
Variable coercion errors (invalid scalar/enum/object values, missing required fields, non-null violations) reports clear and informative error messages.
This only changes error text - error codes and HTTP status codes are unchanged.
Fix doubled _total suffix on Prometheus counters
The built-in Prometheus metrics exporter (/metrics) generated counter names with a
doubled suffix, e.g. hive_router_graphql_errors_total_total instead of
hive_router_graphql_errors_total.
Counter names on /metrics now end in a single _total, matching standard
Prometheus conventions.
OTLP metrics exporter is not affected.
Mask internal error details from client responses
Improve router's error handling by masking internal error details from client responses.
Client-caused errors still return their real message, since it only ever reflects the client's own request. Internal errors now always return a generic "Internal server error" message and never the underlying error message, which previously leaked details such as subgraph URLs, storage/network errors, and other backend internals. The real error is still logged for debugging purposes.
Error codes are unchanged. HTTP status codes are unchanged, except for GraphQL operation normalization and minification failures, which are now correctly treated as router-side bugs and always return 500 (previously 400, or 200 based on Accept header) instead of being treated as a client mistake.
Propagate all multi-instance headers from a single subgraph response
When a subgraph responded with multiple instances of a never-join header (Set-Cookie or WWW-Authenticate), the router only forwarded one of them to the client and silently dropped the rest.
The fix is to propagate all values of a never-join header as separate header fields end-to-end, rather than just the first value.
Fixes #1388
Upgrade Laboratory to latest (v0.2.4)
Upgrade Laboratory to latest version (@graphql-hive/laboratory@0.2.4). This release includes the following changes:
- Schema documentation: browse root types, types and fields, search across the whole type map (including input objects and enum values), and read descriptions, deprecations and argument defaults.
- Builder rows gain an "Open in Docs" context menu entry, and the GraphQL editor hover gains an "Open in Docs" link.
hive-router-plan-executor 7.0.4 (2026-08-12)
Fixes
Add WebSocket connection reuse and execution mode configuration
WebSocket-enabled subgraphs can now configure connection reuse and choose how queries and mutations are transported.
Configure defaults for all subgraphs under traffic_shaping.all.websocket:
subscriptions:
enabled: true
websocket:
subgraphs:
reviews:
path: /reviews/ws
traffic_shaping:
all:
pool_idle_timeout: 50s # default
websocket:
reuse_connections: true
execute_mode: reuse_existingreuse_connections defaults to true:
truemultiplexes matching operations over initialized pooled WebSocket connectionsfalseopens a dedicated connection for each WebSocket operation
execute_mode defaults to http and supports:
http: queries and mutations always use HTTPreuse_existing: queries and mutations use an initialized matching WebSocket when available, otherwise they immediately use HTTPwebsocket: queries and mutations use WebSocket, creating or joining a pooled connection when reuse is enabled
Settings can be overridden per subgraph. Omitted WebSocket fields inherit the global value:
traffic_shaping:
all:
pool_idle_timeout: 50s # default
websocket:
reuse_connections: true
execute_mode: reuse_existing
subgraphs:
payments:
pool_idle_timeout: 5s
websocket:
reuse_connections: false
execute_mode: websocketIn this example, other WebSocket-enabled subgraphs opportunistically reuse initialized connections. payments sends each operation over a dedicated WebSocket.
Pooled WebSockets use the effective pool_idle_timeout. A per-subgraph value overrides traffic_shaping.all.pool_idle_timeout for both HTTP and WebSocket pools. Active WebSocket operations do not expire.
Connection matching uses the inbound headers selected by traffic_shaping.router.dedupe.headers, even when router request deduplication is disabled. Include every header that can affect connection-scoped authentication, authorization, cookies, or tenant identity:
traffic_shaping:
router:
dedupe:
headers:
include: [authorization, cookie, x-tenant]Improve variable coercion error messages
Variable coercion errors (invalid scalar/enum/object values, missing required fields, non-null violations) reports clear and informative error messages.
This only changes error text - error codes and HTTP status codes are unchanged.
Propagate all multi-instance headers from a single subgraph response
When a subgraph responded with multiple instances of a never-join header (Set-Cookie or WWW-Authenticate), the router only forwarded one of them to the client and silently dropped the rest.
The fix is to propagate all values of a never-join header as separate header fields end-to-end, rather than just the first value.
Fixes #1388
hive-router-internal 0.0.42 (2026-08-12)
Fixes
Add WebSocket connection reuse and execution mode configuration
WebSocket-enabled subgraphs can now configure connection reuse and choose how queries and mutations are transported.
Configure defaults for all subgraphs under traffic_shaping.all.websocket:
subscriptions:
enabled: true
websocket:
subgraphs:
reviews:
path: /reviews/ws
traffic_shaping:
all:
pool_idle_timeout: 50s # default
websocket:
reuse_connections: true
execute_mode: reuse_existingreuse_connections defaults to true:
truemultiplexes matching operations over initialized pooled WebSocket connectionsfalseopens a dedicated connection for each WebSocket operation
execute_mode defaults to http and supports:
http: queries and mutations always use HTTPreuse_existing: queries and mutations use an initialized matching WebSocket when available, otherwise they immediately use HTTPwebsocket: queries and mutations use WebSocket, creating or joining a pooled connection when reuse is enabled
Settings can be overridden per subgraph. Omitted WebSocket fields inherit the global value:
traffic_shaping:
all:
pool_idle_timeout: 50s # default
websocket:
reuse_connections: true
execute_mode: reuse_existing
subgraphs:
payments:
pool_idle_timeout: 5s
websocket:
reuse_connections: false
execute_mode: websocketIn this example, other WebSocket-enabled subgraphs opportunistically reuse initialized connections. payments sends each operation over a dedicated WebSocket.
Pooled WebSockets use the effective pool_idle_timeout. A per-subgraph value overrides traffic_shaping.all.pool_idle_timeout for both HTTP and WebSocket pools. Active WebSocket operations do not expire.
Connection matching uses the inbound headers selected by traffic_shaping.router.dedupe.headers, even when router request deduplication is disabled. Include every header that can affect connection-scoped authentication, authorization, cookies, or tenant identity:
traffic_shaping:
router:
dedupe:
headers:
include: [authorization, cookie, x-tenant]hive-router-config 0.1.12 (2026-08-12)
Features
Add WebSocket connection reuse and execution mode configuration
WebSocket-enabled subgraphs can now configure connection reuse and choose how queries and mutations are transported.
Configure defaults for all subgraphs under traffic_shaping.all.websocket:
subscriptions:
enabled: true
websocket:
subgraphs:
reviews:
path: /reviews/ws
traffic_shaping:
all:
pool_idle_timeout: 50s # default
websocket:
reuse_connections: true
execute_mode: reuse_existingreuse_connections defaults to true:
truemultiplexes matching operations over initialized pooled WebSocket connectionsfalseopens a dedicated connection for each WebSocket operation
execute_mode defaults to http and supports:
http: queries and mutations always use HTTPreuse_existing: queries and mutations use an initialized matching WebSocket when available, otherwise they immediately use HTTPwebsocket: queries and mutations use WebSocket, creating or joining a pooled connection when reuse is enabled
Settings can be overridden per subgraph. Omitted WebSocket fields inherit the global value:
traffic_shaping:
all:
pool_idle_timeout: 50s # default
websocket:
reuse_connections: true
execute_mode: reuse_existing
subgraphs:
payments:
pool_idle_timeout: 5s
websocket:
reuse_connections: false
execute_mode: websocketIn this example, other WebSocket-enabled subgraphs opportunistically reuse initialized connections. payments sends each operation over a dedicated WebSocket.
Pooled WebSockets use the effective pool_idle_timeout. A per-subgraph value overrides traffic_shaping.all.pool_idle_timeout for both HTTP and WebSocket pools. Active WebSocket operations do not expire.
Connection matching uses the inbound headers selected by traffic_shaping.router.dedupe.headers, even when router request deduplication is disabled. Include every header that can affect connection-scoped authentication, authorization, cookies, or tenant identity:
traffic_shaping:
router:
dedupe:
headers:
include: [authorization, cookie, x-tenant]hive-router 0.0.88 (2026-08-10)
Features
Add apollo_graphos supergraph source
Adds a new apollo_graphos supergraph source that fetches the supergraph schema from Apollo GraphOS's managed federation Uplink, for routers migrating from Apollo Router/Gateway without needing a separate schema-delivery pipeline.
Configure it with graph_ref and key (or the APOLLO_GRAPH_REF/APOLLO_KEY environment variables), and optionally endpoint (defaults to Apollo's GCP and AWS Uplink endpoints, tried in order), timeout and accept_invalid_certs.
Closes #505
Expose log correlation to the plugin system
Plugins can now attach a custom correlation (e.g. a tenant or project ID) to every log line of the current request via hive_router::set_log_correlation(key, value), callable from any hook, alongside the built-in request_id and trace_id.
Fixes #1350
Expose the request summary to the plugin system
Plugins can now enrich the request summary log line with custom attributes via hive_router::set_summary_attribute(key, value), callable from any hook (e.g. on_http_request, on_graphql_analysis).
Fixes #1368
Expose the summary message to the plugin system
Plugins can now override the request summary log line's message via hive_router::set_summary_message(message), callable from any hook.
Fixes #1378
Fixes
Report persistedDocumentHash in usage reports
Usage reports now include the resolved persisted document id, so Hive Console can match
requests to app deployments and populate their "Last used" data. Previously the router
resolved the document id but always omitted it from the usage report.
Closes #1343
hive-router-plan-executor 7.0.3 (2026-08-10)
Fixes
Add apollo_graphos supergraph source
Adds a new apollo_graphos supergraph source that fetches the supergraph schema from Apollo GraphOS's managed federation Uplink, for routers migrating from Apollo Router/Gateway without needing a separate schema-delivery pipeline.
Configure it with graph_ref and key (or the APOLLO_GRAPH_REF/APOLLO_KEY environment variables), and optionally endpoint (defaults to Apollo's GCP and AWS Uplink endpoints, tried in order), timeout and accept_invalid_certs.
Closes #505
Expose log correlation to the plugin system
Plugins can now attach a custom correlation (e.g. a tenant or project ID) to every log line of the current request via hive_router::set_log_correlation(key, value), callable from any hook, alongside the built-in request_id and trace_id.
Fixes #1350
Expose the request summary to the plugin system
Plugins can now enrich the request summary log line with custom attributes via hive_router::set_summary_attribute(key, value), callable from any hook (e.g. on_http_request, on_graphql_analysis).
Fixes #1368
Expose the summary message to the plugin system
Plugins can now override the request summary log line's message via hive_router::set_summary_message(message), callable from any hook.
Fixes #1378