# Selectors

- Canonical URL: https://docs.fairvisor.com/docs/policy/selectors/
- Section: docs
- Last updated: n/a
> Route matching in policy selectors — hosts, pathExact, pathPrefix, and methods.


A **selector** determines which requests a policy applies to. It is defined per-policy inside `spec.selector`.

## Fields

```json
{
  "selector": {
    "hosts": ["api.example.com"],
    "pathPrefix": "/api/v1/",
    "methods": ["GET", "POST"]
  }
}
```

| Field | Type | Required | Description |
|---|---|---|---|
| `hosts` | array of strings | no | Optional host filter. Exact match against request host (case-insensitive). If absent, all hosts match. |
| `pathPrefix` | string | conditional | Prefix match. Must start with `/`. |
| `pathExact` | string | conditional | Exact path match. Must start with `/`. |
| `methods` | array of strings | no | HTTP method filter. Case-sensitive. If absent, **all methods** match. |

At least one of `pathPrefix` or `pathExact` must be provided.

## Host matching rules

### `hosts`

`hosts` scopes a selector to one or more domain names.

```json
{ "hosts": ["api.example.com", "admin.example.com"], "pathPrefix": "/" }
```

Rules:
- Matching is exact by hostname (no wildcard syntax in v1).
- Matching is case-insensitive.
- Request host is normalized before compare (`API.EXAMPLE.COM` matches `api.example.com`).
- If `hosts` is omitted, selector is host-agnostic and matches any host.

Use `hosts` when one edge instance serves multiple domains and you need per-domain policy isolation.

## Path matching rules

### `pathPrefix`

Matches any path that begins with the given prefix.

The prefix must end with `/` for correct sub-path matching (the engine normalises a missing trailing slash). Exception: the root selector `"pathPrefix": "/"` matches all paths.

```json
{ "pathPrefix": "/api/v1/" }
```

Matches:
- `/api/v1/users`
- `/api/v1/users/123`
- `/api/v1/`

Does not match:
- `/api/v2/users`
- `/api/v10/`

### `pathExact`

Matches only the exact path string.

```json
{ "pathExact": "/v1/chat/completions" }
```

Matches:
- `/v1/chat/completions`

Does not match:
- `/v1/chat/completions/stream`
- `/v1/chat/`

### Both in one selector

A policy can specify both `pathPrefix` and `pathExact`. The route index builds separate trie entries for each, and the policy is matched if **either** applies.

```json
{
  "selector": {
    "hosts": ["api.example.com"],
    "pathPrefix": "/api/",
    "pathExact": "/health"
  }
}
```

## Method filtering

```json
{
  "selector": {
    "hosts": ["api.example.com"],
    "pathPrefix": "/api/",
    "methods": ["POST", "PUT", "PATCH"]
  }
}
```

Only requests whose HTTP method is in the `methods` list will match. The comparison is case-sensitive; use uppercase.

Supported values: `GET`, `POST`, `PUT`, `DELETE`, `PATCH`, `HEAD`, `OPTIONS`, `CONNECT`, `TRACE`.

If `methods` is absent or empty, the selector matches **any** method.

## Multiple policies on the same route

Multiple policies can match the same request. All matched policies are evaluated in the order they appear in `bundle.policies`. A request is only allowed if **all** matching policies allow it.

```json
{
  "policies": [
    {
      "id": "global-limit",
      "spec": {
        "selector": { "pathPrefix": "/" },
        "rules": [{ "name": "global", "limit_keys": ["ip:address"], ... }]
      }
    },
    {
      "id": "api-limit",
      "spec": {
        "selector": {
          "hosts": ["api.example.com"],
          "pathPrefix": "/api/",
          "methods": ["POST"]
        },
        "rules": [{ "name": "api-post", "limit_keys": ["header:x-api-key"], ... }]
      }
    }
  ]
}
```

A `POST https://api.example.com/api/users` request will be evaluated against both policies.

## Route index internals

Selectors are compiled at bundle load time. Matching first filters by host, then performs trie lookup by path segments:

```
host=api.example.com
root
├── api
│   └── v1    ← prefix policies: [api-v1]
│       └── users  ← exact policies: [users-exact]
└── health     ← exact policies: [health-check]
```

Lookup is O(depth) for path traversal within the selected host bucket.

