---
title: "Rate limit"
url: "/reference/filters/network/rate-limit/"
kind: "reference"
summary: "Network filter that checks each new connection against an external gRPC rate limit service."
---

> Arion site index: [/llms.txt](/llms.txt)

# Rate limit

Network filter that checks each new connection against an external gRPC rate limit service.

| Attachment | Type URL (`@type`) | Per-route override | Build feature |
|---|---|---|---|
| Filter chain (`filters`) | `type.googleapis.com/envoy.extensions.filters.network.ratelimit.v3.RateLimit` | Not applicable | None |

## What it does

The network rate limit filter calls a rate limit service (RLS) such as [envoyproxy/ratelimit](https://github.com/envoyproxy/ratelimit) over gRPC for every new connection and drops the connection when the service answers over-limit. When the RLS response carries a quota, Arion caches it process-wide for the quota window, so subsequent connections consume a local bucket without a round-trip; one connection refreshes the quota when it expires. Configure it per filter chain, before the terminal filter.

## Minimal configuration

From `arion-runtime-global-rate-limit.yaml`; the fragment sits under `filter_chains[].filters`:

```yaml,arion=fragment
- name: ratelimit
  typed_config:
    "@type": type.googleapis.com/envoy.extensions.filters.network.ratelimit.v3.RateLimit
    stat_prefix: global_ratelimit
    domain: api.example.com
    failure_mode_deny: true
    descriptors:
      - entries:
          - key: destination_cluster
            value: api
    rate_limit_service:
      grpc_service:
        envoy_grpc:
          cluster_name: rls
```

## Fields

| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| `stat_prefix` | string | Yes | — | Prefix for this filter's statistics. |
| `domain` | string | See note | — | RLS namespace sent with every check. Optional only on listeners with a [TLS inspector](@/reference/filters/listener/tls-inspector.md): when omitted, the connection's TLS SNI becomes the domain, giving each server name its own quota namespace. On listeners without a TLS inspector it is mandatory and startup fails otherwise. |
| `failure_mode_deny` | bool | No | `false` | Drop the connection when the RLS is unreachable. When `false`, connections pass on RLS failure. |
| `descriptors` | list | Yes | — | Static descriptors sent with every check; each is a list of `{key, value}` entries. Dynamic descriptors from connection or request attributes are not supported. |
| `rate_limit_service.grpc_service` | object | Yes | — | The RLS target: `envoy_grpc.cluster_name` (a cluster speaking HTTP/2) or `google_grpc.target_uri`, plus an optional `timeout`. |

A configured `domain` always wins over the SNI. The top-level Envoy `timeout` field is unsupported — set the timeout inside `grpc_service` instead.

## Ordering and interactions

At most one rate limit filter per chain, always before the terminal filter. At runtime it fires after the [connection limit](@/reference/filters/network/connection-limit.md) and before [network RBAC](@/reference/filters/network/rbac.md). Because the filter chain is selected by SNI first, the limiter is already scoped to the matched tenant when it runs; rejected clients see a closed connection, not an HTTP 429.
