Skip to main content

a6-plugin-traffic-split

Overview

The traffic-split plugin dynamically directs portions of traffic to different upstream services based on custom rules (match) and weighted distributions (weighted_upstreams). Use it for canary releases, blue-green deployments, and A/B testing — all without modifying DNS or load balancers.

When to Use

  • Canary release: gradually shift traffic to a new version (10% → 50% → 100%)
  • Blue-green deployment: switch traffic based on request headers or cookies
  • A/B testing: split traffic by user attributes (headers, query params, cookies)
  • Feature flags: route specific users to feature branches
  • Multi-version API: run multiple backend versions simultaneously

Plugin Configuration Reference (Route/Service)

Top-level

FieldTypeRequiredDefaultDescription
rulesarray[object]YesList of traffic splitting rules. Each rule has optional match and required weighted_upstreams.

rules[].match

FieldTypeRequiredDefaultDescription
matcharray[object]No[]Conditions to activate this rule. Empty = unconditional (all traffic uses weights).
match[].varsarray[array]NoVariable expressions: ["variable", "operator", "value"]. Uses Nginx variables. Multiple vars in one object = AND. Multiple objects in match = OR.

Operators: ==, ~=, >, <, >=, <=, ~~ (regex match), !~~, in, has, ! — see lua-resty-expr.

Common variables: arg_name (query param), http_header-name (request header), cookie_name (cookie value).

rules[].weighted_upstreams[]

FieldTypeRequiredDefaultDescription
upstream_idstring/integerNoID of a pre-configured upstream object. Use this to get health checks, retries, etc.
upstreamobjectNoInline upstream configuration (see below).
weightintegerNo1Traffic weight for this upstream.

If only weight is set (no upstream or upstream_id), traffic goes to the route's default upstream.

Inline upstream object

FieldTypeRequiredDefaultDescription
typestringNo"roundrobin"Load balancing: "roundrobin" or "chash".
nodesobjectYesBackend nodes as {"host:port": weight}.
timeoutobjectNo15 (seconds){"connect": N, "send": N, "read": N}
pass_hoststringNo"pass""pass" = client host, "node" = upstream node, "rewrite" = use upstream_host.
upstream_hoststringNoCustom Host header. Only works with pass_host: "rewrite".
namestringNoHuman-readable name for the upstream.

Not supported in inline upstream: service_name, discovery_type, checks, retries, retry_timeout, scheme. Use upstream_id for these features.

Step-by-Step: Enable traffic-split on a Route

1. Canary release — 20% to new version

a6 route create -f - <<'EOF'
{
"id": "canary-release",
"uri": "/api/*",
"plugins": {
"traffic-split": {
"rules": [
{
"weighted_upstreams": [
{
"upstream": {
"name": "new-version-v2",
"type": "roundrobin",
"nodes": {
"backend-v2:8080": 1
}
},
"weight": 2
},
{
"weight": 8
}
]
}
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"backend-v1:8080": 1
}
}
}
EOF

Result: 20% traffic → backend-v2, 80% → backend-v1 (route default).

2. Blue-green deployment — header-based switching

a6 route create -f - <<'EOF'
{
"id": "blue-green",
"uri": "/api/*",
"plugins": {
"traffic-split": {
"rules": [
{
"match": [
{
"vars": [
["http_x-canary", "==", "true"]
]
}
],
"weighted_upstreams": [
{
"upstream": {
"name": "green-env",
"type": "roundrobin",
"nodes": {
"green-backend:8080": 1
}
},
"weight": 1
}
]
}
]
}
},
"upstream": {
"type": "roundrobin",
"nodes": {
"blue-backend:8080": 1
}
}
}
EOF

Result: Requests with header x-canary: true → green, all others → blue.

3. Increase canary to 50%

a6 route update canary-release -f - <<'EOF'
{
"plugins": {
"traffic-split": {
"rules": [
{
"weighted_upstreams": [
{
"upstream": {
"name": "new-version-v2",
"type": "roundrobin",
"nodes": {
"backend-v2:8080": 1
}
},
"weight": 5
},
{
"weight": 5
}
]
}
]
}
}
}
EOF

Common Patterns

A/B testing by query parameter

{
"plugins": {
"traffic-split": {
"rules": [
{
"match": [
{
"vars": [
["arg_variant", "==", "B"]
]
}
],
"weighted_upstreams": [
{
"upstream": {
"name": "variant-B",
"type": "roundrobin",
"nodes": {"variant-b:8080": 1}
}
}
]
}
]
}
}
}

Requests with ?variant=B → variant B backend.

Multi-rule routing (OR logic)

{
"plugins": {
"traffic-split": {
"rules": [
{
"match": [{"vars": [["http_x-api-id", "==", "1"]]}],
"weighted_upstreams": [
{"upstream": {"type": "roundrobin", "nodes": {"svc-a:8080": 1}}}
]
},
{
"match": [{"vars": [["http_x-api-id", "==", "2"]]}],
"weighted_upstreams": [
{"upstream": {"type": "roundrobin", "nodes": {"svc-b:8080": 1}}}
]
}
]
}
}
}

Using upstream_id for health checks

{
"plugins": {
"traffic-split": {
"rules": [
{
"weighted_upstreams": [
{
"upstream_id": "canary-upstream",
"weight": 2
},
{
"weight": 8
}
]
}
]
}
}
}

Pre-create the upstream with a6 upstream create to configure health checks, retries, and other advanced settings.

Multi-condition AND match

{
"match": [
{
"vars": [
["arg_name", "==", "jack"],
["http_user-id", ">", "23"],
["http_x-env", "~~", "^(staging|canary)$"]
]
}
]
}

All three conditions must be true (AND logic within a single vars array).

Match Logic Reference

StructureLogic
Multiple entries in one vars arrayAND — all must match
Multiple objects in match arrayOR — any can match
Empty match or no matchUnconditional — always applies weights

Troubleshooting

SymptomCauseFix
Traffic ratio inaccurateRound-robin algorithm causes slight deviationExpected behavior; ratios converge over many requests
Match rule not triggeringVariable name wrong or operator mismatchUse http_header-name for headers, arg_name for query params
Health checks not workingInline upstream doesn't support checksUse upstream_id referencing a pre-created upstream with health checks
All traffic going to defaultMatch conditions never trueDebug with a6 route get and verify header/param names
Weight 0 not blocking trafficWeight 0 means "never forward" to that upstreamCorrect — set weight to 0 to exclude an upstream

Config Sync Example

version: "1"
routes:
- id: canary-api
uri: /api/*
plugins:
traffic-split:
rules:
- weighted_upstreams:
- upstream_id: canary-upstream
weight: 2
- weight: 8
upstream_id: stable-upstream
upstreams:
- id: stable-upstream
type: roundrobin
nodes:
"stable-backend:8080": 1
- id: canary-upstream
type: roundrobin
nodes:
"canary-backend:8080": 1

This page is generated from a6-plugin-traffic-split/SKILL.md in the api7/a6 repository. Browse all skills on the AI Agent Skills page.

API7.ai Logo

The digital world is connected by APIs,
API7.ai exists to make APIs more efficient, reliable, and secure.

Sign up for API7 newsletter

Product

API7 Gateway

SOC2 Type IIISO 27001HIPAAGDPRRed Herring

Copyright © APISEVEN PTE. LTD 2019 – 2026. Apache, Apache APISIX, APISIX, and associated open source project names are trademarks of the Apache Software Foundation