Envoy Envoy

Envoy Architecture: Listeners, Clusters, and Filter Chains

How a request actually moves through Envoy, from the socket it arrives on to the upstream it's sent to.

9 min Beginner

Envoy’s design follows directly from its founding goal: make the network transparent to applications, and make it fast to tell a network problem from an application problem. That goal shapes the vocabulary, listeners, clusters, filters, that every piece of Envoy configuration is built from. This guide covers what each one does and how a request moves through them.

Downstream and upstream

Envoy calls whatever sends it a request downstream and whatever it forwards that request to upstream. Downstream can be an end user’s browser, another service in the mesh, anything opening a connection to Envoy. Upstream is wherever Envoy decides to route the request: an application instance, another service, an external API. Every piece of configuration in Envoy sits on one side of that line or the other.

Listeners: where connections come in

A listener binds to a port and accepts connections on it. A single Envoy instance can define several listeners, each with its own port and its own processing pipeline, so one instance can, for example, terminate TLS on 443 while handling plain traffic on 8080 with entirely different rules. Whatever a listener needs to do with a connection before it can be routed, TLS termination, protocol detection, and more, happens through the filters attached to it, which the next guide in this series covers in depth.

Clusters: where connections go

A cluster is a named, logical group of one or more upstream endpoints that Envoy can route traffic to. If you’re coming from Kubernetes, the comparison that tends to click: a cluster is roughly analogous to a Service, and the individual endpoints inside it are roughly analogous to the Pods behind it. Envoy tracks each endpoint’s health, applies whatever load-balancing policy the cluster is configured with, and picks a target from among the healthy ones for each request.

Filters and filter chains

Once a listener accepts a connection, the data flows through a sequence of filters, small, focused units that each do one job, chained together into a filter chain. The most basic filters operate at the network level (TCP or UDP), on the raw byte stream, before anything has been parsed as a higher-level protocol. Envoy ships with network filters for things like MongoDB, Redis, and Kafka protocol handling out of the box.

For HTTP traffic specifically, one particular network filter does most of the heavy lifting: the HTTP Connection Manager, which parses the raw bytes into HTTP requests, headers, and bodies, and exposes its own nested chain of HTTP-level filters, access logging, retries, header manipulation, and more, that operate once the traffic is HTTP rather than just bytes. The next guide in this series is dedicated entirely to it.

Routes: choosing a cluster

Once traffic reaches the HTTP layer, routes decide which cluster a given request goes to, matched against characteristics of the request itself: host, path, headers. A request to example.com/api might match a route that sends it to an example-com cluster, while a different host or path matches a different route entirely. Route matching is what turns “some HTTP request arrived” into “here is the specific cluster it belongs to.”

Putting it together: the path of a request

downstream client
      │
      ▼
   listener (bound to a port)
      │
      ▼
  filter chain (network filters, then HTTP Connection Manager)
      │
      ▼
   route matching (host, path, headers)
      │
      ▼
    cluster (a named group of endpoints)
      │
      ▼
  load balancing + health checking
      │
      ▼
 upstream endpoint

A request arrives on a listener, flows through that listener’s filter chain, gets matched to a cluster by the routing rules, and Envoy’s cluster manager picks a healthy endpoint within that cluster to actually send it to. Everything Envoy does, TLS, rate limiting, retries, observability, attaches to one of these stages rather than existing as a separate concern, which is exactly the “network is transparent, problems are easy to localize” design the project set out to achieve: because every stage is explicit and inspectable, a slow response or a failed request can usually be traced to a specific listener, filter, or cluster rather than requiring a guess.

For a considerably more detailed account of exactly what happens at each stage, including the parts of the architecture (worker threads, connection pooling) this guide deliberately simplifies, Envoy’s own “life of a request” documentation goes step by step through the full internal flow.

Popular Guides