
# Traffic Splitting Policy

The traffic splitting policy randomly distributes incoming requests across a set
of weighted base paths. It selects one base path per request and writes it to
the request custom context, where a URL Rewrite or URL Forward handler can use
it to route the request. This is useful for blue/green rollouts, canary
releases, or splitting traffic between backends.

## Configuration

The configuration shows how to configure the policy in the 'policies.json' document.

```json title="config/policies.json"
{
  "name": "my-traffic-splitting-inbound-policy",
  "policyType": "traffic-splitting-inbound",
  "handler": {
    "export": "TrafficSplittingInboundPolicy",
    "module": "$import(@zuplo/runtime)",
    "options": {
      "basePaths": [
        {
          "url": "https://api-v1.example.com",
          "weight": 80
        },
        {
          "url": "https://api-v2.example.com",
          "weight": 15
        },
        {
          "url": "$env(CANARY_BASE_URL)",
          "weight": 5
        }
      ],
      "customOutputProperty": "trafficSplitting.basePath",
      "logSelection": true
    }
  }
}
```

### Policy Configuration

- `name` <code className="text-green-600">&lt;string&gt;</code> - The name of your policy instance. This is used as a reference in your routes.
- `policyType` <code className="text-green-600">&lt;string&gt;</code> - The identifier of the policy. This is used by the Zuplo UI. Value should be `traffic-splitting-inbound`.
- `handler.export` <code className="text-green-600">&lt;string&gt;</code> - The name of the exported type. Value should be `TrafficSplittingInboundPolicy`.
- `handler.module` <code className="text-green-600">&lt;string&gt;</code> - The module containing the policy. Value should be `$import(@zuplo/runtime)`.
- `handler.options` <code className="text-green-600">&lt;object&gt;</code> - The options for this policy. [See Policy Options](#policy-options) below.

### Policy Options

The options for this policy are specified below. All properties are optional unless specifically marked as required.

- `basePaths` **(required)** <code className="text-green-600">&lt;object[]&gt;</code> - The set of base paths (URLs) to split traffic across. One entry is selected at random per request, weighted by its `weight`.
  - `url` **(required)** <code className="text-green-600">&lt;string&gt;</code> - The base path (URL) to route to when this entry is selected. Supports environment variables, e.g. `$env(BASE_URL)/v2`.
  - `weight` **(required)** <code className="text-green-600">&lt;number&gt;</code> - The relative weight for this base path. Higher weights receive proportionally more traffic. Weights are relative and do not need to add up to 100.
- `customOutputProperty` **(required)** <code className="text-green-600">&lt;string&gt;</code> - A simple dotted property path under the request custom context where the selected URL is written (e.g. `trafficSplitting.basePath`). Reference it later in a URL Rewrite `rewritePattern` or URL Forward `baseUrl` as `${context.custom.trafficSplitting.basePath}`. Only one value is in effect; if multiple Traffic Splitting policies write the same property, the last one to run wins. Array indexes and brackets are not allowed.
- `logSelection` <code className="text-green-600">&lt;boolean&gt;</code> - When `true`, logs which base path was selected for each request. Defaults to `false`. Defaults to `false`.

## Using the Policy

On each request this policy selects one of the configured `basePaths` at random,
weighted by each entry's `weight`. Weights are relative — they do not need to
add up to 100. The selected URL is written to the request custom context at the
path given by `customOutputProperty`.

### Using the selected base path

The selected URL is stored on `context.custom` and is intended to be consumed by
a later handler on the same route. Reference it using the `customOutputProperty`
path you configured. For example, with
`"customOutputProperty": "trafficSplitting.basePath"`:

```json
// URL Rewrite handler
{
  "handler": {
    "export": "urlRewriteHandler",
    "module": "$import(@zuplo/runtime)",
    "options": {
      "rewritePattern": "${context.custom.trafficSplitting.basePath}/users/${params.id}"
    }
  }
}
```

```json
// URL Forward handler
{
  "handler": {
    "export": "urlForwardHandler",
    "module": "$import(@zuplo/runtime)",
    "options": {
      "baseUrl": "${context.custom.trafficSplitting.basePath}"
    }
  }
}
```

> The `redirect` handler's `location` is not interpolated — use the URL Rewrite
> or URL Forward handler to route to the selected base path.

### Only one value is in effect

`customOutputProperty` resolves to a single value. If more than one Traffic
Splitting policy on a route writes to the same property, the **last policy to
run wins** — its selection is the one the handler sees. In practice you should
configure a single Traffic Splitting policy per output property.

### Environment variables

Because each `url` is a string value, you can reference environment variables in
it, including mixed strings:

```json
{
  "basePaths": [
    { "url": "$env(STABLE_BASE_URL)", "weight": 90 },
    { "url": "$env(CANARY_BASE_URL)/v2", "weight": 10 }
  ],
  "customOutputProperty": "trafficSplitting.basePath"
}
```

### Logging the selection

Set `"logSelection": true` to log which base path was selected on each request.
This is off by default.

Read more about [how policies work](/articles/policies)
