# Conditionally Disable Global Plugins

Global plugins apply to all routes by default, which is useful for enforcing organization-wide policies such as logging, rewriting, or traffic controls. However, some routes may need to be exempt from certain global plugins.

This guide walks you through how to conditionally disable global plugins for specific routes using route labels and the `_meta.filter` mechanism.

## How It Works[​](#how-it-works "Direct link to How It Works")

The approach uses three components:

1. **Route labels**: A label (e.g., `api7_disable_global_rules: response-rewrite`) on routes that should skip certain global plugins.
2. **`serverless-pre-function`**: A global serverless function that reads the route label and registers it as a custom NGINX variable.
3. **`_meta.filter`**: A condition on the global plugin that evaluates the variable and skips execution when it matches.

## Prerequisites[​](#prerequisites "Direct link to Prerequisites")

* An API7 Enterprise instance is running.
* A Gateway Group is created and a Gateway instance is running.
* A [token from the Dashboard](https://docs.api7.ai/api7-gateway/reference/obtain-dashboard-token.md).

## Option 1: Regex Match (Recommended)[​](#option-1-regex-match-recommended "Direct link to Option 1: Regex Match (Recommended)")

This approach returns the raw route label string and uses a regex filter on the global plugin. It was validated end to end in the local API7 Gateway environment with a global `response-rewrite` rule.

### Step 1: Create the Serverless Function[​](#step-1-create-the-serverless-function "Direct link to Step 1: Create the Serverless Function")

Configure the `serverless-pre-function` as a global plugin that registers a custom variable from the route label:

* Admin API
* ADC

```
curl -k "https://localhost:7443/apisix/admin/global_rules/serverless-pre-function?gateway_group_id={gateway_group_id}" -X PUT \

  -H "X-API-KEY: ${API_KEY}" \

  -H "Content-Type: application/json" \

  -d '{

    "plugins": {

      "serverless-pre-function": {

        "phase": "rewrite",

        "functions": [

          "return function(conf, ctx) local core = require \"apisix.core\" core.ctx.register_var(\"api7_disable_global_rules\", function(ctx) local route = ctx.matched_route and ctx.matched_route.value if route and route.labels then return route.labels.api7_disable_global_rules end return 1 end) end"

        ]

      }

    }

  }'
```

adc.yaml

```
global_rules:

  serverless-pre-function:

    phase: rewrite

    functions:

      - |-

        return function(conf, ctx)

            local core = require "apisix.core"

            core.ctx.register_var("api7_disable_global_rules", function(ctx)

                local route = ctx.matched_route and ctx.matched_route.value

                if route and route.labels then

                    return route.labels.api7_disable_global_rules

                end

                return 1

            end)

        end
```

This command updates global rules only. Services, routes, and consumers stay in place. Global rules absent from the file are removed. Preview the diff:

```
adc diff -f adc.yaml \

  --include-resource-type global_rule
```

Synchronize the reviewed configuration:

```
adc sync -f adc.yaml \

  --include-resource-type global_rule
```

### Step 2: Configure the Global Plugin with `_meta.filter`[​](#step-2-configure-the-global-plugin-with-_metafilter "Direct link to step-2-configure-the-global-plugin-with-_metafilter")

Add `_meta.filter` to the global plugin you want to conditionally skip. The following example applies a response header globally unless the route label contains `response-rewrite`:

* Admin API
* ADC

```
curl -k "https://localhost:7443/apisix/admin/global_rules/response-rewrite?gateway_group_id={gateway_group_id}" -X PUT \

  -H "X-API-KEY: ${API_KEY}" \

  -H "Content-Type: application/json" \

  -d '{

    "plugins": {

      "response-rewrite": {

        "headers": {

          "set": {

            "X-Global-Rule": "applied"

          }

        },

        "_meta": {

          "filter": [

            ["api7_disable_global_rules", "!", "~~", ".*response-rewrite.*"]

          ]

        }

      }

    }

  }'
```

adc.yaml

```
global_rules:

  serverless-pre-function:

    phase: rewrite

    functions:

      - |-

        return function(conf, ctx)

            local core = require "apisix.core"

            core.ctx.register_var("api7_disable_global_rules", function(ctx)

                local route = ctx.matched_route and ctx.matched_route.value

                if route and route.labels then

                    return route.labels.api7_disable_global_rules

                end

                return 1

            end)

        end

  response-rewrite:

    headers:

      set:

        X-Global-Rule: applied

    _meta:

      filter:

        - - api7_disable_global_rules

          - "!"

          - "~~"

          - ".*response-rewrite.*"
```

Keep the Step 1 global rule in this file. This command updates global rules only. Services, routes, and consumers stay in place. Global rules absent from the file are removed. Preview the diff:

```
adc diff -f adc.yaml \

  --include-resource-type global_rule
```

Synchronize the reviewed configuration:

```
adc sync -f adc.yaml \

  --include-resource-type global_rule
```

### Step 3: Label Routes to Skip the Plugin[​](#step-3-label-routes-to-skip-the-plugin "Direct link to Step 3: Label Routes to Skip the Plugin")

Add the `api7_disable_global_rules` label to routes that should bypass the global plugin.

* Admin API
* ADC

```
# 1. Create a Service for the routes

curl -k "https://localhost:7443/apisix/admin/services/global-exemption-service?gateway_group_id={gateway_group_id}" -X PUT \

  -H "X-API-KEY: ${API_KEY}" \

  -H "Content-Type: application/json" \

  -d '{

    "name": "global-exemption-service",

    "upstream": {

      "type": "roundrobin",

      "nodes": [

        {

          "host": "httpbin.org",

          "port": 80,

          "weight": 100

        }

      ]

    }

  }'



# 2. Create a labeled route that skips the global plugin

curl -k "https://localhost:7443/apisix/admin/routes/global-exempt-route?gateway_group_id={gateway_group_id}" -X PUT \

  -H "X-API-KEY: ${API_KEY}" \

  -H "Content-Type: application/json" \

  -d '{

    "name": "global-exempt-route",

    "paths": ["/anything/global-exempt"],

    "methods": ["GET"],

    "labels": {

      "api7_disable_global_rules": "response-rewrite"

    },

    "service_id": "global-exemption-service"

  }'



# 3. Create a normal route where the global plugin still applies

curl -k "https://localhost:7443/apisix/admin/routes/global-protected-route?gateway_group_id={gateway_group_id}" -X PUT \

  -H "X-API-KEY: ${API_KEY}" \

  -H "Content-Type: application/json" \

  -d '{

    "name": "global-protected-route",

    "paths": ["/anything/global-protected"],

    "methods": ["GET"],

    "service_id": "global-exemption-service"

  }'
```

adc.yaml

```
services:

  - name: global-exemption-service

    upstream:

      nodes:

        - host: httpbin.org

          port: 80

          weight: 1

    routes:

      - name: global-exempt-route

        uris:

          - /anything/global-exempt

        labels:

          api7_disable_global_rules: response-rewrite

      - name: global-protected-route

        uris:

          - /anything/global-protected

    labels:

      docs-example: global-exemption-service
```

Preview the changes owned by this example and confirm that the diff contains no unintended updates or deletions:

```
adc diff -f adc.yaml \

  --include-resource-type service \

  --label-selector docs-example=global-exemption-service
```

Synchronize the reviewed configuration:

```
adc sync -f adc.yaml \

  --include-resource-type service \

  --label-selector docs-example=global-exemption-service
```

### Verify[​](#verify "Direct link to Verify")

Send a request to the labeled route:

```
curl -i "http://127.0.0.1:9080/anything/global-exempt"
```

The response should not include the `X-Global-Rule` header because `response-rewrite` is skipped.

Send a request to the non-labeled route:

```
curl -i "http://127.0.0.1:9080/anything/global-protected"
```

The response should include `X-Global-Rule: applied` because the global plugin is active.

## Option 2: List-Based Match[​](#option-2-list-based-match "Direct link to Option 2: List-Based Match")

This approach returns a list of plugin names from the label and uses the `has` operator in `_meta.filter`.

caution

Complex regex expressions may incur more processing overhead compared to the list-based approach.

### Serverless Function[​](#serverless-function "Direct link to Serverless Function")

Use this variant when you prefer exact list membership checks for comma-separated labels:

adc.yaml

```
global_rules:

  serverless-pre-function:

    phase: rewrite

    functions:

      - >-

        return function(conf, ctx)

            local core = require "apisix.core"

            core.ctx.register_var("api7_disable_global_rules", function(ctx)

                local route = ctx.matched_route and ctx.matched_route.value

                if route and route.labels then

                    local value = route.labels.api7_disable_global_rules

                    if value then

                        local disable_plugins = {}

                        for plugin_name in string.gmatch(value, "[^,]+") do

                            local trimmed_name = string.gsub(plugin_name, "^%s*(.-)%s*$", "%1")

                            if trimmed_name and trimmed_name ~= "" then

                                table.insert(disable_plugins, trimmed_name)

                            end

                        end

                        return disable_plugins

                    end

                end

                return 1

            end)

        end
```

### Global Plugin with `has` Filter[​](#global-plugin-with-has-filter "Direct link to global-plugin-with-has-filter")

Use the `has` operator to check whether the returned list contains the plugin name:

adc.yaml

```
global_rules:

  response-rewrite:

    _meta:

      filter:

        - - api7_disable_global_rules

          - "!"

          - has

          - response-rewrite

    headers:

      set:

        X-Global-Rule: applied
```

## Understanding `_meta.filter`[​](#understanding-_metafilter "Direct link to understanding-_metafilter")

The `_meta` field is available on every plugin and supports the following options:

| Field            | Type          | Description                                                                      |
| ---------------- | ------------- | -------------------------------------------------------------------------------- |
| `disable`        | boolean       | Disable the plugin entirely                                                      |
| `error_response` | string/object | Custom error response when the plugin rejects a request                          |
| `priority`       | integer       | Override the plugin's execution priority                                         |
| `filter`         | array         | Runtime expression; the plugin is skipped if the expression evaluates to `false` |

The `filter` field uses the same expression syntax as route matching (`radixtree` vars). Supported operators include `==`, `!=`, `~~` (regex), `has` (list contains), and more.

## Additional Resources[​](#additional-resources "Direct link to Additional Resources")

* [Plugins](https://docs.api7.ai/api7-gateway/key-concepts/plugins.md)
* [Built-in Variables](https://docs.api7.ai/api7-gateway/reference/built-in-variables.md)
