Open-Source Wikis

/

Envoy

/

Features

/

HTTP filters

envoyproxy/envoy

HTTP filters

HTTP filters are the L7 plugins that run inside the HTTP connection manager. At the time of writing, source/extensions/filters/http/ ships 71 filters in core and a handful more in contrib/. This page is the family overview; for a particular filter's configuration, see envoyproxy.io.

What an HTTP filter does

A filter implements Http::StreamFilter — a base class with decoder and encoder halves. For each request stream it can:

  • Inspect or rewrite request headers, body, trailers, metadata.
  • Inspect or rewrite response headers, body, trailers, metadata.
  • Stop iteration and resume after an async event (callout, JWT verification, file read).
  • Generate a local reply (short-circuit) instead of forwarding.
  • Read or write StreamInfo and per-route configuration.

Decoder filters run in declared order; encoder filters run in reverse declared order. The terminal decoder filter is almost always the router.

Categories

The 71 in-tree filters break down roughly into:

Category Examples Path
Terminal router, tcp_proxy (network) router/
Authn / Authz jwt_authn, ext_authz, oauth2, basic_auth, api_key_auth, rbac, mcp jwt_authn/
Rate limiting ratelimit, local_ratelimit, rate_limit_quota, admission_control ratelimit/
External processing ext_proc, ext_authz, gcp_authn, aws_lambda, aws_request_signing ext_proc/
Buffering / fault injection buffer, fault, bandwidth_limit, bandwidth_share, kill_request, file_system_buffer buffer/
Compression compressor, decompressor compressor/
Caching cache, cache_v2 cache_v2/
Headers / metadata header_mutation, header_to_metadata, set_metadata, set_filter_state, cors, csrf, ip_tagging, cdn_loop, geoip, credential_injector many
Routing helpers on_demand, dynamic_forward_proxy, original_src many
Protocol bridges grpc_http1_bridge, grpc_http1_reverse_bridge, grpc_web, grpc_json_transcoder, grpc_json_reverse_transcoder, connect_grpc_bridge grpc_*/
Stats / extraction grpc_stats, grpc_field_extraction, proto_message_extraction, proto_api_scrubber, tap, json_to_metadata, sse_to_metadata, thrift_to_metadata many
Stateful sessions stateful_session, composite, match_delegate many
Custom responses / overrides custom_response, health_check, direct_response, transform many
AI plumbing mcp, mcp_json_rest_bridge, mcp_router, a2a new in 2025
Scriptable lua, wasm, dynamic_modules lua/, wasm/, dynamic_modules/

There are also dual-mode filters — ext_authz, rbac, local_ratelimit, ratelimit, wasm, dynamic_modules, set_filter_state, match_delegate, geoip — that have both an HTTP and a network variant.

Anatomy of a filter

A filter directory typically contains:

source/extensions/filters/http/<name>/
├── BUILD                # Bazel target
├── <name>_filter.h      # The Filter class
├── <name>_filter.cc
├── config.h             # Factory wrapper
├── config.cc            # Factory + REGISTER_FACTORY
└── (optional) matcher.cc, async_clients.cc, ...

The filter implements:

class MyFilter : public Http::PassThroughFilter {
  Http::FilterHeadersStatus decodeHeaders(Http::RequestHeaderMap&, bool end_stream) override;
  Http::FilterDataStatus    decodeData(Buffer::Instance&, bool end_stream) override;
  Http::FilterHeadersStatus encodeHeaders(Http::ResponseHeaderMap&, bool end_stream) override;
  // ... encodeData, decodeTrailers, encodeTrailers, on1xxHeaders, ...
};

Many filters subclass Http::PassThroughFilter (envoy/http/filter.h) which defaults all callbacks to "continue".

The factory implements Server::Configuration::NamedHttpFilterConfigFactory:

class MyFilterConfigFactory : public Common::FactoryBase<MyFilterConfigProto> {
  Http::FilterFactoryCb createFilterFactoryFromProtoTyped(...) override;
  std::string name() const override { return "envoy.filters.http.my_filter"; }
};

REGISTER_FACTORY(MyFilterConfigFactory,
                 Server::Configuration::NamedHttpFilterConfigFactory);

REGISTER_FACTORY puts a static initializer in the binary that registers the factory at process start, so simply linking the filter into the binary (via extensions_build_config.bzl) is what makes it available.

Per-route configuration

Filters can opt into per-route configuration via typed_per_filter_config. The base class is Router::RouteSpecificFilterConfig; the filter exposes getConfig helpers that read the most specific override (route → vhost → route_config). Most non-trivial filters use this.

Async filters

Filters that need to call out (ext_authz, jwt_authn JWKS fetch, oauth2, gcp_authn) follow the canonical async pattern in filter manager: return StopIteration, kick off an async client request via the cluster manager, then call decoder_callbacks_->continueDecoding() on completion.

Stats

Each filter gets a Stats::Scope from the HCM. The convention is to emit counters under <filter_name>.<event>, e.g. ext_authz.ok, ext_authz.error, ext_authz.denied, jwt_authn.allowed. Histograms are emitted for callout latencies.

Match delegate and composite

Two filters deserve a special mention because they wrap others:

Both let you do per-request filter selection without writing custom code.

Adding a new HTTP filter

The end-to-end recipe:

  1. Pick a name in the envoy.filters.http.* namespace.
  2. Create source/extensions/filters/http/<name>/ with BUILD, *_filter.{h,cc}, config.{h,cc}.
  3. Define the proto under api/envoy/extensions/filters/http/<name>/v3/.
  4. Register the filter in source/extensions/extensions_build_config.bzl (or all_extensions.bzl for non-removable ones).
  5. Add a CODEOWNERS entry and a extensions_metadata.yaml entry.
  6. Add unit tests under test/extensions/filters/http/<name>/.
  7. Add an integration test if behaviour is end-to-end-visible.
  8. Add a release note in changelogs/current.yaml.
  9. Read extension policy and confirm the filter belongs in core (or use contrib/ if it doesn't).

The simplest reference for boilerplate is header_mutation — small, no async work, no per-route config. The most complex is ext_proc — async, streaming, mode changes, multiple side conversations.

See also

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

HTTP filters – Envoy wiki | Factory