---
title: "Routing"
url: "/docs/traffic/routing/"
kind: "feature"
summary: "Match HTTP requests by host, path, headers and query, then forward, split, redirect, rewrite or answer them directly."
---

> Arion site index: [/llms.txt](/llms.txt)

# Routing

Match HTTP requests by host, path, headers and query, then forward, split, redirect, rewrite or answer them directly.

Routing decides what happens to each HTTP request: the connection manager picks a virtual host by the request's authority, then walks that host's routes in order and takes the first match. Use it to send traffic to clusters, split by weight, redirect, rewrite, or answer without an upstream.

This page maps what a route can do; the [route reference](@/reference/resources/routes.md) has the full field tables.

## A route configuration

```yaml,arion=fragment
route_config:
  name: local_routes
  virtual_hosts:
    - name: api
      domains: ["api.example.com"]
      routes:
        - match: { prefix: "/" }
          route: { cluster: api }
```

`domains` accepts exact hosts, suffix wildcards (`*.example.com`), prefix wildcards (`example.*`), and the catch-all `*`. The most specific domain wins across virtual hosts: exact beats suffix, suffix beats prefix, and longer matches beat shorter ones.

## Matching requests

A `match` combines a path rule with optional header and query-parameter rules; all must hold:

```yaml,arion=fragment
- match:
    path_separated_prefix: "/api/v1"   # or prefix, path (exact), safe_regex
    headers:
      - name: ":method"
        string_match: { exact: "GET" }
    query_parameters:
      - name: version
        string_match: { exact: "v1" }
  route: { cluster: api }
```

Path rules are `prefix`, `path` (exact), `safe_regex`, or `path_separated_prefix` (matches `/api/v1` and `/api/v1/...` but not `/api/v1beta`); set `case_sensitive: false` to ignore case. Header matchers support exact, prefix, suffix, contains, regex and present patterns, plus `invert_match`; the pseudo-headers `:method`, `:path` and `:scheme` are matchable. Query parameters match by string pattern or presence.

## Actions

Each route takes exactly one action. Route to a cluster (as above), split across weighted clusters:

```yaml,arion=fragment
route:
  weighted_clusters:
    clusters:
      - name: api-v1
        weight: 90
      - name: api-v2
        weight: 10
```

pick the cluster from a request header (`route: { cluster_header: x-cluster }`), redirect:

```yaml,arion=fragment
redirect:
  response_code: MOVED_PERMANENTLY
  host_redirect: example.com
  path_redirect: "/new"
```

or answer directly:

```yaml,arion=fragment
direct_response:
  status: 404
  body: { inline_string: "not found" }
```

## Rewrites

A route action can rewrite the path before forwarding — `prefix_rewrite` replaces the matched prefix, `regex_rewrite` applies a pattern; the two are mutually exclusive:

```yaml,arion=fragment
route:
  cluster: api
  prefix_rewrite: "/internal"
```

## Header mutation

Request and response headers can be added or removed at the route configuration, virtual host, and route levels:

```yaml,arion=fragment
request_headers_to_add:
  - header: { key: x-env, value: prod }
    append_action: OVERWRITE_IF_EXISTS_OR_ADD
request_headers_to_remove: [x-debug]
```

By default outer levels apply last and win; set `most_specific_header_mutations_wins: true` on the route configuration to reverse that.

## Timeouts, retries, and upgrades

A route's upstream `timeout` defaults to 15s; `timeout: 0s` disables it. A `retry_policy` on the route or virtual host retries safe failures — see [health checks and resilience](@/docs/traffic/health-checks-and-resilience.md). WebSocket upgrades are enabled per connection manager or per route:

```yaml,arion=fragment
route:
  cluster: api
  upgrade_configs:
    - upgrade_type: websocket
```

HTTP CONNECT upgrades are not supported.

Routes can also come from a control plane instead of the file: point the connection manager at `rds` with an ADS config source and the same route configuration arrives over xDS — see [xDS control planes](@/docs/operate/xds-control-planes.md).

## Verify

Send a request with the virtual host's domain:

```bash
curl -s -H "Host: api.example.com" http://127.0.0.1:8080/api/v1/status -o /dev/null -w "%{http_code}\n"
```

```text
200
```

## Limits

- First match wins — order routes from most to least specific, catch-all last.
- CONNECT upgrades, request mirroring, and hedging are not supported.
- Weighted-cluster entries carry only `name` and `weight`; per-entry header mutation is not supported.
- Header `range_match` and route-level CORS policy are not supported (CORS is an [HTTP filter](@/reference/filters/http/cors.md)).
- Per-route filter overrides (`typed_per_filter_config`) must name a configured filter; replacement config is accepted for the local rate limit and RBAC filters only.

Every match, action, and policy field is listed in the [route reference](@/reference/resources/routes.md).
