> ## Documentation Index
> Fetch the complete documentation index at: https://tyk.io/docs/llms.txt
> Use this file to discover all available pages before exploring further.

# Path Modification

> Learn how to configure URL rewriting in Tyk Gateway to modify request paths before forwarding to upstream services, including triggers, rules, dynamic rewrite targets, and internal routing

Before forwarding a matched request, Tyk Gateway can rewrite the request path. This handles two common situations: where the path a client uses differs from the path the upstream service expects, and where the destination should be determined by the content of the request rather than the incoming URL.

Path modification is applied by the **URL rewrite** middleware, which is configured at the endpoint level in the API definition.

## How It Works

The URL rewrite middleware uses **triggers** to determine when and how to rewrite the request path. Each trigger combines one or more matching conditions with a rewrite target.

### The Basic Trigger

The basic trigger tests the request path against a regular expression. It serves as a control switch for the middleware: if the path does not match, no rewriting takes place, regardless of any advanced triggers configured.

When the regex includes capturing groups - subexpressions wrapped in parentheses - each matched group is assigned an index: `$1` for the first, `$2` for the second, and so on. These captured values can appear anywhere in the [rewrite target](#the-rewrite-target).

For example, the pattern `/(\\w+)/(\\w+)` applied to `/fiction/9780` captures `fiction` as `$1` and `9780` as `$2`. A rewrite target of `category/$1?id=$2` would resolve to `category/fiction?id=9780`.

<Note>
  When testing the request path, Tyk handles percent-encoded characters in two passes. If the pattern does not match the raw URL, Tyk decodes percent-encoded characters (for example, `%2D` to `-`) and tries again. Only the raw and fully decoded forms are checked.
</Note>

### Advanced Triggers

Advanced triggers are optional and are only evaluated after the basic trigger fires. Each advanced trigger tests one or more elements of the request against a regular expression. The testable elements are:

| Element          | Description                                                                              |
| :--------------- | :--------------------------------------------------------------------------------------- |
| Query parameter  | A named URL query string value                                                           |
| Request header   | An HTTP request header; use the normalized form, for example `X-Preview` not `x-preview` |
| Path parameter   | An individual segment of the request path, matched by splitting the path on `/`          |
| Request body     | The full request body; no element name required                                          |
| Session metadata | A named field in the metadata attached to the current session                            |
| Request context  | A named context variable such as client IP address or JWT claim                          |

An advanced trigger can test multiple elements, combined with `any` (at least one must match) or `all` (every element must match). Any individual test can be negated, so the condition passes when the element does not match the pattern.

Advanced triggers are evaluated in the order they are defined. The first to fire is applied and the rest are skipped. If none fire, the basic trigger's rewrite target is used.

When an advanced trigger fires, the value of each request element that was tested is stored and made available in the rewrite target.

## The Rewrite Target

Each trigger specifies a rewrite target: a static path or a dynamically constructed string. The following sources of dynamic values are available:

**Captured path segments from the basic trigger** - the `$1`, `$2`, ... groups extracted by the basic trigger regex. These are available in any trigger's rewrite target, not just the basic trigger's own. This is how path segment values are made available when an advanced trigger fires.

**Request element values from advanced triggers** - when an advanced trigger fires, each element value it tested is available as `$tyk_context.trigger-{n}-{name}-{i}`, where:

* `n` is the trigger's position in the list, zero-based.
* `name` is the element name (for example, `region` for a query parameter named `region`).
* `i` is the index within the element, used when an element can return multiple values (such as a repeated header).

For example, in the configuration shown in the [Worked Example](#worked-example) below, advanced trigger 1 (the first in the list, so `n=0`) tests the `region` query parameter. When it fires on a request with `?region=us`, the value `us` is available as:

```
$tyk_context.trigger-0-region-0
                     ↑  ↑      ↑
                     n  name   i
```

The `i` index is `0` because `region` has a single value. For elements that can carry multiple values - for example a header sent twice in the same request - successive values are indexed from `0`: `$tyk_context.trigger-0-X-Tag-0`, `$tyk_context.trigger-0-X-Tag-1`, and so on.

If the pattern for an advanced trigger rule contains capturing groups, those captured substrings are also stored and are accessible with an additional index `j` appended: `$tyk_context.trigger-{n}-{name}-{i}-{j}`, where `j` is zero-based and corresponds to the first, second, and so on capturing group in the pattern. For example, a pattern `(\\w+)-(\\w+)` applied to a header value `eu-west` would store `eu` as `$tyk_context.trigger-0-X-Region-0-0` and `west` as `$tyk_context.trigger-0-X-Region-0-1`.

**Session metadata** - using the `$tyk_meta.` namespace.

**Key-value storage** - using the [appropriate KV reference notation](/tyk-configuration-reference/kv-store#transformation-middleware).

<Note>
  Consul and Vault KV references must appear at the end of the rewrite target. Tyk's token-matching pattern treats `/` as a valid key character, so a reference placed mid-path - for example `upstream/$secret_consul.myKey/suffix` - will match `$secret_consul.myKey/suffix` as the token and attempt to look up the key `myKey/suffix` rather than `myKey`. This limitation does not apply to environment variables or Gateway `secrets`.
</Note>

The target can be a path on the same upstream, a fully qualified URL on a different host, or a `tyk://` internal address to route the request to another API on the same Tyk Gateway instance. See [Internal Routing](/advanced-configuration/transform-traffic/looping).

## Matching Behaviour

The URL rewrite middleware applies its own regular expression matching to the request path. It does not use the endpoint matching mode (wildcard, prefix, suffix, or exact) configured at the Gateway level, and is not affected by changes to those settings. See [Request Matching](/getting-started/key-concepts/url-matching) for details on endpoint matching modes.

## Configuration

### Tyk OAS

The middleware is configured in the `operations` section of the Tyk Vendor Extension (`x-tyk-api-gateway`), under the `operationId` for the endpoint.

#### Basic Trigger

Enable the middleware and set `pattern` and `rewriteTo`:

```json theme={null}
"urlRewrite": {
  "enabled": true,
  "pattern": "/(\\w+)/(\\w+)",
  "rewriteTo": "books-service/$1/$2"
}
```

In this example, a request to `GET /fiction/9780` matches the pattern, capturing `fiction` as `$1` and `9780` as `$2`. The path is rewritten to `books-service/fiction/9780`.

#### Advanced Triggers

Add a `triggers` array to the `urlRewrite` object. Each entry specifies `condition` (`any` or `all`), `rules`, and `rewriteTo`. Rules use the following fields:

| Field     | Description                                                                                 |
| :-------- | :------------------------------------------------------------------------------------------ |
| `in`      | Key location: `path`, `query`, `header`, `sessionMetadata`, `requestBody`, `requestContext` |
| `name`    | Key name (not required when `in` is `requestBody`)                                          |
| `pattern` | Regular expression to test against the key value                                            |
| `negate`  | `true` to pass the rule when the pattern does not match                                     |

```json theme={null}
"urlRewrite": {
  "enabled": true,
  "pattern": "/(\\w+)/(\\w+)",
  "rewriteTo": "books-service/$1/$2",
  "triggers": [
    {
      "condition": "all",
      "rewriteTo": "regional-books-service/$tyk_context.trigger-0-region-0/$1/$2",
      "rules": [
        { "in": "query",  "name": "region",    "pattern": "\\w+", "negate": false },
        { "in": "header", "name": "X-Preview", "pattern": "true", "negate": true }
      ]
    },
    {
      "condition": "any",
      "rewriteTo": "preview-books-service/$1/$2",
      "rules": [
        { "in": "header", "name": "X-Preview", "pattern": "true", "negate": false }
      ]
    }
  ]
}
```

The first advanced trigger fires when a `region` query parameter is present AND `X-Preview` is not `true`. The second fires when `X-Preview` is `true`. If neither fires, the basic trigger routes to `books-service`.

#### API Designer

1. **Add an endpoint** - From the API Designer, add an endpoint for the path and method to modify.

2. **Select the URL Rewrite middleware** - Select **ADD MIDDLEWARE** and choose **URL Rewrite**.

3. **Configure the basic trigger** - Enter the match pattern and the rewrite target.

   <img src="https://mintcdn.com/tyk/jzHiRUIhvyphWUhc/img/dashboard/api-designer/tyk-oas-url-rewrite-basic.png?fit=max&auto=format&n=jzHiRUIhvyphWUhc&q=85&s=5a98e6b540a2dd8b17136f78f5dbbb15" alt="Configuring the basic trigger" width="1237" height="586" data-path="img/dashboard/api-designer/tyk-oas-url-rewrite-basic.png" />

4. **Optionally configure advanced triggers** - Select **ADD TRIGGER** for each additional trigger. Use **ADD RULE** to add rules to each trigger.

   <img src="https://mintcdn.com/tyk/jzHiRUIhvyphWUhc/img/dashboard/api-designer/tyk-oas-url-rewrite-advanced.png?fit=max&auto=format&n=jzHiRUIhvyphWUhc&q=85&s=b24adbeee400a9f7f7e6002d693178a4" alt="Configuring advanced trigger rules" width="1237" height="347" data-path="img/dashboard/api-designer/tyk-oas-url-rewrite-advanced.png" />

5. **Save the API** - Select **ADD MIDDLEWARE**, then **SAVE API**.

### Tyk Classic

If using Tyk Classic, add a `url_rewrites` object to the `extended_paths` section of the API definition. To reference context variables in `rewrite_to`, [enable context variables](/api-management/traffic-transformation/request-context-variables#enabling-context-variables-for-use-with-tyk-classic-apis) for the API.

#### Basic Trigger

```json theme={null}
"url_rewrites": [
  {
    "path": "/{category}/{id}",
    "method": "GET",
    "match_pattern": "/(\\w+)/(\\w+)",
    "rewrite_to": "books-service/$1/$2"
  }
]
```

#### Advanced Triggers

Add a `triggers` array to the `url_rewrites` entry. Each trigger specifies `on` (`any` or `all`), `options` (the rules, nested by key location), and `rewrite_to`. The key location fields are:

| Field                     | Location                 |
| :------------------------ | :----------------------- |
| `header_matches`          | Request header           |
| `query_val_matches`       | Query parameter          |
| `path_part_matches`       | Path parameter           |
| `session_meta_matches`    | Session metadata         |
| `payload_matches`         | Request body             |
| `request_context_matches` | Request context variable |

Each rule specifies `match_rx` (the pattern) and `reverse` (`true` to pass when the pattern does not match).

```json theme={null}
"triggers": [
  {
    "on": "all",
    "options": {
      "query_val_matches": {
        "region": { "match_rx": "\\w+", "reverse": false }
      },
      "header_matches": {
        "X-Preview": { "match_rx": "true", "reverse": true }
      }
    },
    "rewrite_to": "regional-books-service/$tyk_context.trigger-0-region-0/$1/$2"
  },
  {
    "on": "any",
    "options": {
      "header_matches": {
        "X-Preview": { "match_rx": "true", "reverse": false }
      }
    },
    "rewrite_to": "preview-books-service/$1/$2"
  }
]
```

The first trigger fires when a `region` query parameter is present AND `X-Preview` is not `true`. The second fires when `X-Preview` is `true`.

#### API Designer

1. **Add an endpoint** - From the Endpoint Designer, add an endpoint and select the **URL Rewrite** plugin.

2. **Configure the basic trigger** - Add the match pattern and the rewrite target.

   <img src="https://mintcdn.com/tyk/_n1j2nedxXfbDX-s/img/2.10/url_rewrite_settings.png?fit=max&auto=format&n=_n1j2nedxXfbDX-s&q=85&s=3989dc00f7297a44d082fde1334a7a77" alt="URL rewrite basic trigger configuration" width="1212" height="445" data-path="img/2.10/url_rewrite_settings.png" />

3. **Optionally configure advanced triggers** - Select **Create Advanced Trigger**. Triggers can be edited or removed in the **Advanced URL Rewrite** section.

   <img src="https://mintcdn.com/tyk/_n1j2nedxXfbDX-s/img/2.10/url_rewrite-advanced-edit.png?fit=max&auto=format&n=_n1j2nedxXfbDX-s&q=85&s=8aef4487671db98bdc6f64d502f8b81d" alt="Advanced trigger list" width="1211" height="389" data-path="img/2.10/url_rewrite-advanced-edit.png" />

4. **Save the API** - Select **Save** or **Create**.

### Tyk Operator

Tyk Operator supports both Tyk OAS and Tyk Classic API definitions. The URL rewrite middleware is configured in the same way as described above for each format - in the `operations` section of the Tyk Vendor Extension for Tyk OAS, or in `extended_paths.url_rewrites` for Tyk Classic.

See [Tyk Operator](/api-management/automations/operator) for details on creating and managing API definitions with Tyk Operator.

## Worked Example

This example shows basic and advanced triggers working together on an endpoint `GET /{category}/{id}` that routes book catalog requests to different upstream services depending on the region and whether the request is a preview.

**Configuration:**

* **Basic trigger** - pattern `/(\\w+)/(\\w+)` matches the path, capturing the category as `$1` and the book ID as `$2`. Rewrite target: `books-service/$1/$2`.
* **Advanced trigger 1** (`all`) - fires when the `region` query parameter is present AND the `X-Preview` header is not `true` (negated). Rewrite target: `regional-books-service/$tyk_context.trigger-0-region-0/$1/$2`.
* **Advanced trigger 2** (`any`) - fires when the `X-Preview` header is `true`. Rewrite target: `preview-books-service/$1/$2`.

**Outcomes:**

| Request                                    | Path rewritten to                        |
| :----------------------------------------- | :--------------------------------------- |
| `GET /fiction/9780?region=us`              | `regional-books-service/us/fiction/9780` |
| `GET /fiction/9780` with `X-Preview: true` | `preview-books-service/fiction/9780`     |
| `GET /fiction/9780`                        | `books-service/fiction/9780`             |

For the first request, advanced trigger 1 fires: `region=us` satisfies condition 1, and `X-Preview` is absent so the negated condition 2 passes. The rewrite target combines the captured region (`$tyk_context.trigger-0-region-0`) with `$1` and `$2` from the basic trigger.

For the second request, the `region` parameter is absent so trigger 1 does not fire. Trigger 2 fires on the `X-Preview` header.

For the third request, neither advanced trigger fires and the basic trigger's target is used.

**Tyk OAS configuration:**

```json theme={null}
"urlRewrite": {
  "enabled": true,
  "pattern": "/(\\w+)/(\\w+)",
  "rewriteTo": "books-service/$1/$2",
  "triggers": [
    {
      "condition": "all",
      "rewriteTo": "regional-books-service/$tyk_context.trigger-0-region-0/$1/$2",
      "rules": [
        { "in": "query",  "name": "region",    "pattern": "\\w+", "negate": false },
        { "in": "header", "name": "X-Preview", "pattern": "true", "negate": true }
      ]
    },
    {
      "condition": "any",
      "rewriteTo": "preview-books-service/$1/$2",
      "rules": [
        { "in": "header", "name": "X-Preview", "pattern": "true", "negate": false }
      ]
    }
  ]
}
```
