Hive RouterGuides

Dynamic Subgraph Routing

Sometimes you need to route requests to different instances of the same subgraph based on the request properties - maybe for testing new versions, handling different regions, or managing load. Hive Router lets you change where requests go dynamically using simple logic expressions.

This guide shows you practical ways to use dynamic routing in real-world scenarios. For the complete configuration reference, see override_subgraph_urls configuration.

How It Works

Dynamic routing uses expressions to decide where to send requests. For each request, the router evaluates your expression and routes to the URL it returns.

What you have access to:

  • .request - The incoming HTTP request (headers, method, etc.)
  • .request.path_params - Path parameters captured by the configured http.graphql_endpoint pattern (e.g. tenant from graphql_endpoint: /{tenant}/graphql)
  • .default - The default URL from your supergraph schema
  • .subgraph.name - The name of the subgraph the URL is being resolved for

Per-subgraph overrides live under subgraphs, keyed by subgraph name. Simple example configuration that routes based on a runtime condition:

router.config.yaml
override_subgraph_urls:
  subgraphs:
    subgraph_name:
      url:
        expression: |
          if .request.headers."x-use-special-instance" == "true" {
            "https://special-instance.com/graphql"
          } else {
            .default  # Always provide a fallback
          }

You can also define a single all override that applies to every subgraph without its own entry, which is handy when the routing logic is shared across subgraphs:

router.config.yaml
override_subgraph_urls:
  all:
    url:
      expression: |
        if .subgraph.name == "reviews" {
          "https://reviews.example.com/graphql"
        } else {
          .default
        }

Examples

To illustrate how dynamic routing can be used, here are some common scenarios, along with example configurations.

Canary Deployments

One of the most common use cases for dynamic routing is canary deployment. This pattern allows you to roll out a new version of a subgraph to a small, controlled subset of traffic before releasing it to all users.

router.config.yaml
override_subgraph_urls:
  subgraphs:
    products:
      url:
        expression: |
          if .request.headers."x-deploy-track" == "canary" {
            "https://products-canary.example.com/graphql"
          } else {
            .default
          }

With this configuration, your QA team or CI/CD pipeline can test the new deployment in production by simply adding the X-Deploy-Track: canary header to their requests, without affecting regular users.

router.config.yaml
override_subgraph_urls:
  subgraphs:
    products:
      url:
        expression: |
          # Route 10% of traffic to canary
          if random_int(1, 100) <= 10 {
            "https://products-canary.example.com/graphql"
          } else {
            .default
          }

Regional Routing

If your application is deployed globally, you likely have subgraph instances in multiple geographic regions. Routing users to the instance closest to them can significantly reduce latency.

router.config.yaml
override_subgraph_urls:
  subgraphs:
    reviews:
      url:
        expression: |
          region = .request.headers."x-user-region" || "unknown"

          if region == "us-east" {
            "https://reviews-us-east.example.com/graphql"
          } else if region == "eu-west" {
            "https://reviews-eu-west.example.com/graphql"
          } else if region == "asia-pacific" {
            "https://reviews-ap.example.com/graphql"
          } else {
            # Default to primary region
            .default
          }

Multi-Tenant Routing with Path Parameters

If your GraphQL endpoint embeds a tenant (or other) identifier in its path, you can capture it with http.graphql_endpoint and read it from .request.path_params. Combined with an all override, this routes every subgraph based on the matched segment:

router.config.yaml
http:
  graphql_endpoint: /{tenant}/graphql

override_subgraph_urls:
  all:
    url:
      expression: |
        tenant = string!(.request.path_params.tenant)
        replace(string!(.default), "/api/", "/api/" + tenant + "/")

A request to /acme/graphql resolves tenant to "acme" before the expression runs.