# Lists

Lists let you define named sets of values and reference them with the `{{list.<key>}}` syntax, avoiding duplicated IPs, paths, and other values across rules. Lists can be defined in two places:

- **In the tenant config** (`tenant.json`) — scoped to that tenant
- **In a shared common config** (`common.json`) — available to all tenants

If a list with the same key exists in both files, the **tenant-level list takes precedence**.

> [View Schema Definition](/tenant-schema.html#lists)

## Defining Lists

Lists are defined in the top-level `lists` object. Each key maps to an array of strings.

```json
{
  "tenant_id": "my-app",
  "lists": {
    "blocked_ips": ["192.0.2.0/24", "198.51.100.0/24"],
    "api_paths": ["/api/v1/*", "/api/v2/*"],
    "bot_agents": ["curl/7*", "python-requests*"]
  },
  "delivery_config": { ... },
  "security_config": { ... }
}
```

```json
{
  "lists": {
    "monitoring_paths": ["/health", "/status", "/metrics"],
    "corporate_ips": ["198.51.100.0/24", "203.0.113.0/24"],
    "trusted_asns": ["12345", "67890"]
  }
}
```

Both files use the same `lists` structure. Any list defined in either file can be referenced with `{{list.<key>}}` from any tenant config.

## Referencing Lists

Use `{{list.<key>}}` anywhere a match condition or security exception accepts values. The syntax is the same regardless of whether the list is defined in `tenant.json` or `common.json`.

### In Delivery Match Conditions

```json
{
  "lists": {
    "blocked_ips": ["192.0.2.0/24", "198.51.100.0/24"],
    "api_paths": ["/api/v1/*", "/api/v2/*"]
  },
  "delivery_config": {
    "version": "1.0",
    "onClientRequest": {
      "features": {
        "respondWith": {
          "rules": [{
            "matchAll": { "ipv4": "{{list.blocked_ips}}" },
            "args": { "status": 403, "body": "Forbidden" }
          }]
        },
        "caching": {
          "rules": [{
            "matchAll": { "paths": "{{list.api_paths}}" },
            "args": { "ttl_seconds": 60 }
          }]
        }
      }
    }
  }
}
```

### In Security Exceptions

```json
{
  "security_config": {
    "deny_groups": ["SQL-INJECTION-ANOMALY", "REP"],
    "exceptions": {
      "SQL-INJECTION-ANOMALY": {
        "paths": ["{{list.monitoring_paths}}", "/internal/metrics"],
        "v4_ips": ["{{list.corporate_ips}}", "203.0.113.50"]
      },
      "REP": {
        "asn": ["{{list.trusted_asns}}", "55555"]
      }
    }
  }
}
```

List references and inline values can be mixed in the same array — the list entries are expanded and merged with the inline values at runtime. Standalone references (e.g., `"v4_ips": "{{list.corporate_ips}}"`) also work when no inline values are needed.

### Mixing with Inline Values

List references can be combined with inline values in the same array. The list entries are expanded and merged with the inline values.

```json
{
  "matchAll": {
    "ipv4": ["{{list.blocked_ips}}", "203.0.113.0/24"],
    "reqheader": { "User-Agent": "{{list.bot_agents}}" }
  }
}
```

## Common Config Setup

The common config file must be named `common.json` and hosted alongside your tenant configs. To enable it, set the Property Manager variable `PMUSER_TENANT_COMMON` to `"true"`. When enabled, the EdgeWorker fetches `common.json` alongside the tenant config, making shared lists available for `{{list.*}}` references. If both files define a list with the same name, the tenant-level list takes precedence — common lists are never merged with tenant lists.

## Override Behavior

When a tenant defines a list with the same key as one in `common.json`, the **tenant-level list takes precedence**. This lets individual tenants customize shared values without affecting other tenants.

```json
{
  "lists": {
    "trusted_ips": ["198.51.100.0/24"]
  }
}
```

```json
{
  "lists": {
    "trusted_ips": ["203.0.113.0/24", "198.51.100.50"]
  },
  "security_config": {
    "deny_groups": ["SQL-INJECTION-ANOMALY"],
    "exceptions": {
      "SQL-INJECTION-ANOMALY": {
        "v4_ips": "{{list.trusted_ips}}"
      }
    }
  }
}
```

Here, `{{list.trusted_ips}}` resolves to `["203.0.113.0/24", "198.51.100.50"]` — the tenant's values, not the common config's.

## Quick Reference

| Behavior | Description |
| --- | --- |
| **Defined in** | `tenant.json` (per-tenant) and/or `common.json` (shared across tenants) |
| **Single ref** | `"{{list.name}}"` — field value is replaced by the list entries |
| **Mixed array** | `["{{list.name}}", "/inline"]` — list entries expanded and merged with inline values |
| **Override** | Tenant-level list wins when both `tenant.json` and `common.json` define the same key |
| **Missing list** | Resolves to an empty array — no match / no exception applied |
| **Works in** | Match condition values, security exception fields (`paths`, `v4_ips`, `v6_ips`, `asn`) |
| **Enable common config** | Set `PMUSER_TENANT_COMMON` to `"true"` in Property Manager |
