skills/a6-plugin-traffic-split/SKILL.md
Skill for configuring the Apache APISIX traffic-split plugin via the a6 CLI. Covers weighted traffic splitting between upstreams with conditional match rules. Includes canary release, blue-green deployment, A/B testing patterns, and common operational workflows.
npx skillsauth add moonming/a6 a6-plugin-traffic-splitInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
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.
| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| rules | array[object] | Yes | — | List of traffic splitting rules. Each rule has optional match and required weighted_upstreams. |
| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| match | array[object] | No | [] | Conditions to activate this rule. Empty = unconditional (all traffic uses weights). |
| match[].vars | array[array] | No | — | Variable 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).
| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| upstream_id | string/integer | No | — | ID of a pre-configured upstream object. Use this to get health checks, retries, etc. |
| upstream | object | No | — | Inline upstream configuration (see below). |
| weight | integer | No | 1 | Traffic weight for this upstream. |
If only weight is set (no upstream or upstream_id), traffic goes to the route's default upstream.
| Field | Type | Required | Default | Description |
|-------|------|----------|---------|-------------|
| type | string | No | "roundrobin" | Load balancing: "roundrobin" or "chash". |
| nodes | object | Yes | — | Backend nodes as {"host:port": weight}. |
| timeout | object | No | 15 (seconds) | {"connect": N, "send": N, "read": N} |
| pass_host | string | No | "pass" | "pass" = client host, "node" = upstream node, "rewrite" = use upstream_host. |
| upstream_host | string | No | — | Custom Host header. Only works with pass_host: "rewrite". |
| name | string | No | — | Human-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.
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).
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.
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
{
"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.
{
"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}}}
]
}
]
}
}
}
{
"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.
{
"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).
| Structure | Logic |
|-----------|-------|
| Multiple entries in one vars array | AND — all must match |
| Multiple objects in match array | OR — any can match |
| Empty match or no match | Unconditional — always applies weights |
| Symptom | Cause | Fix |
|---------|-------|-----|
| Traffic ratio inaccurate | Round-robin algorithm causes slight deviation | Expected behavior; ratios converge over many requests |
| Match rule not triggering | Variable name wrong or operator mismatch | Use http_header-name for headers, arg_name for query params |
| Health checks not working | Inline upstream doesn't support checks | Use upstream_id referencing a pre-created upstream with health checks |
| All traffic going to default | Match conditions never true | Debug with a6 route get and verify header/param names |
| Weight 0 not blocking traffic | Weight 0 means "never forward" to that upstream | Correct — set weight to 0 to exclude an upstream |
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
tools
Core skill for working with the a6 CLI — the Apache APISIX command-line tool. Provides project conventions, command patterns, architecture overview, and development workflow. Load this skill when working on a6 source code, adding new commands, writing tests, or modifying any a6 component.
tools
Recipe skill for implementing multi-tenant API gateway patterns using the a6 CLI. Covers tenant isolation via Consumer Groups, host/path/header-based routing, per-tenant rate limiting, context forwarding with proxy-rewrite, and declarative config sync workflows for multi-tenant management.
tools
Recipe skill for configuring mutual TLS (mTLS) using the a6 CLI. Covers SSL certificate management, upstream mTLS to backend services, client certificate verification, and end-to-end mTLS setup from client through APISIX to upstream.
tools
Recipe skill for configuring upstream health checks using the a6 CLI. Covers active health checks (HTTP probing), passive health checks (response analysis), combining both, configuring healthy/unhealthy thresholds, and monitoring upstream node status.