Envoy HTTP Filter Phases

Envoy filter chain phases and well-known HTTP filter names with order.

Reference for the Envoy proxy HTTP filter chain: the decode and encode phases, the terminal router filter, and a catalogue of common built-in HTTP filters such as ext_authz, jwt_authn and ratelimit. It runs free in your browser on Gera Tools, with nothing uploaded.

Last updated Source: Gera Tools

In what order do Envoy HTTP filters run?

On the request (decode) path filters run top to bottom in the order they appear in the chain. On the response (encode) path they run in reverse, bottom to top. So a filter added last sees the response first and the request last.

The Envoy HTTP filter chain

Envoy processes every HTTP request through an ordered chain of filters in its HTTP Connection Manager. Filters run in two directions — decode on the way in, encode on the way out — and the chain always ends in the terminal router filter. This reference lists the phases and a catalogue of the most common built-in filters.

How it works

A request flows down the chain through the decode phases, hits the router which forwards it upstream, and the response flows back up through the encode phases in reverse order:

decodeHeaders -> decodeData -> decodeTrailers -> [router] upstream
encodeHeaders <- encodeData <- encodeTrailers <- upstream response

Each filter implements callbacks for these phases and returns a status (Continue, StopIteration, StopAllIterationAndBuffer) to control flow. Many filters touch only headers; others buffer the body. Because encode runs in reverse, ordering matters: place authentication before transcoding, and rate limiting before the router.

Common built-in HTTP filters

Filter namePurpose
envoy.filters.http.routerTerminal filter — selects cluster and forwards
envoy.filters.http.jwt_authnValidates JWT tokens locally against configured JWKS
envoy.filters.http.ext_authzDelegates authz decision to an external gRPC/HTTP service
envoy.filters.http.rbacRole-based access control from connection/request attributes
envoy.filters.http.ratelimitGlobal rate limiting via external RLS service
envoy.filters.http.local_ratelimitPer-instance token-bucket rate limiting, no external dep
envoy.filters.http.corsAdds CORS preflight handling and headers
envoy.filters.http.grpc_json_transcoderTranscodes REST to gRPC and back
envoy.filters.http.compressorGzip/Brotli response compression
envoy.filters.http.wasmEmbeds a WebAssembly extension
envoy.filters.http.faultInjects delays and abort errors for chaos testing
envoy.filters.http.luaRuns Lua scripts for lightweight request/response mutation

The order in which you place filters is consequential. A practical ordering for a secure service mesh is:

  1. Authentication first (jwt_authn, then ext_authz) — reject unauthenticated requests as early as possible, before buffering the body.
  2. RBAC — once the identity is verified, enforce policy.
  3. Rate limiting (local_ratelimit or ratelimit) — shed excess traffic after auth so rate-limit state is not consumed by unauthenticated requests.
  4. Transformation (grpc_json_transcoder, lua, wasm) — mutate the request after it has been allowed through.
  5. Observability (tracing, header modifications) — add headers that downstream services read.
  6. router — always last.

Filter flow control

Each decode callback returns one of three statuses:

  • Continue — hand control to the next filter in the chain immediately.
  • StopIteration — pause the chain; useful for async checks (for example, an ext_authz call waiting for a gRPC response). The filter resumes the chain when the check completes.
  • StopAllIterationAndBuffer — stop and accumulate the request body; used when a filter needs the complete body before deciding (for example, a body-signing verification filter).

Understanding these return values matters when writing custom C++ or Wasm filter extensions, and also when debugging why a filter appears to “hang” a request — it usually means a StopIteration is never resumed.

Tips

  • The router filter (envoy.filters.http.router) is terminal and must be last in the chain.
  • Order auth filters (jwt_authn, ext_authz, rbac) early so unauthorised requests stop quickly.
  • local_ratelimit is per-instance and dependency-free; ratelimit is global via an external RLS.
  • Transform filters like grpc_json_transcoder and wasm sit between auth and the router.