---
title: "Local rate limit"
url: "/reference/filters/http/local-rate-limit/"
kind: "reference"
summary: "HTTP filter that rate-limits requests with an in-process token bucket, overridable per route."
---

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

# Local rate limit

HTTP filter that rate-limits requests with an in-process token bucket, overridable per route.

| Attachment | Type URL (`@type`) | Per-route override | Build feature |
|---|---|---|---|
| HTTP filter chain (`http_filters`) | `type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit` | Yes — same type URL, or wrapped in `envoy.config.route.v3.FilterConfig` | None |

## What it does

The local rate limit filter charges every request one token from an in-process token bucket and answers over-limit requests directly with a configurable status code — no external service involved. The bucket is shared by all connections served by the filter chain, so the limit applies to the aggregate request rate. For per-caller limits keyed on a header, see the [user rate limit](@/reference/filters/http/user-rate-limit.md) filter.

## Minimal configuration

The fragment is an entry in `http_filters`, before the router:

```yaml,arion=fragment
- name: local_ratelimit
  typed_config:
    "@type": type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
    stat_prefix: http_local_rate_limiter
    token_bucket:
      max_tokens: 100
      tokens_per_fill: 10
      fill_interval: 1s
```

## Fields

| Field | Type | Required | Default | Description |
|---|---|---|---|---|
| `stat_prefix` | string | No | — | Prefix for this filter's statistics. |
| `status` | `{code}` | No | `429` | HTTP status returned to rate-limited requests. |
| `token_bucket.max_tokens` | uint32 | Yes | — | Bucket capacity: the largest burst admitted at once. |
| `token_bucket.tokens_per_fill` | uint32 | No | `1` | Tokens added per fill; must be greater than zero. |
| `token_bucket.fill_interval` | duration | Yes | — | Refill period. |

`token_bucket` itself may be omitted, in which case the filter admits everything — useful as a chain-level placeholder that individual routes override. Envoy's `descriptors`, `filter_enabled`, `filter_enforced`, `rate_limits` and related fields are unsupported and refused at startup.

## Per-route override

Routes can replace the bucket through `typed_per_filter_config`, keyed by the filter's name in the chain. Pass a `LocalRateLimit` directly, or wrap one in `envoy.config.route.v3.FilterConfig` (whose `disabled: true` switches the filter off for that route):

```yaml,arion=fragment
routes:
  - match: { prefix: "/expensive" }
    route: { cluster: api }
    typed_per_filter_config:
      local_ratelimit:
        "@type": type.googleapis.com/envoy.extensions.filters.http.local_ratelimit.v3.LocalRateLimit
        stat_prefix: expensive_route
        token_bucket:
          max_tokens: 5
          tokens_per_fill: 1
          fill_interval: 1s
```

The override must name an existing filter of the same type, or the configuration is rejected.

## Ordering and interactions

Place the filter after authentication and authorization if limits should count only accepted traffic, or before them to shed load as early as possible. Over-limit requests short-circuit the chain — the router and any later filter never see them.
