API Gateway Pattern: Centralizing Cross-Cutting Concerns
Once a system is split into more than a handful of services, every client shouldn't need to know where each one lives or repeat the same authentication check against all of them. An API gateway exists to take that burden off both sides.
Published July 6, 2026Without a gateway, a mobile app talking to ten backend services needs to know all ten hostnames, handle authentication against each one individually, and cope with each service's own quirks around rate limiting and error formats. An API gateway sits in front of all of them as a single entry point: the client only ever talks to the gateway, and the gateway routes each request to the right internal service based on the path, header, or other criteria.
client -> gateway -> /users/* -> user-service
-> /orders/* -> order-service
-> /payments/* -> payment-service
What actually lives in the gateway layer
Authentication and authorization are the most common tenant: validating a token once, at the gateway, means individual services don't each need to reimplement token validation and can trust a header the gateway attaches after verifying identity. Rate limiting per client or per API key belongs here too, since enforcing it centrally is far simpler than every service tracking its own counters and getting inconsistent limits. Request logging, TLS termination, and response caching for cacheable endpoints round out the usual list — all things that are genuinely the same concern regardless of which backend service eventually handles the request, and that are wasteful and error-prone to duplicate across every service individually.
The backend-for-frontend variation
A single generic gateway shape doesn't always fit every client well — a mobile app and a web dashboard often want meaningfully different response shapes, pagination sizes, or aggregated data from the same underlying services. The backend-for-frontend pattern runs a separate, thin gateway layer per client type, each shaped specifically for that client's needs, rather than forcing every client through one generic gateway that has to compromise between all of their requirements. This adds another service to operate, so it's usually reserved for cases where client needs have genuinely diverged, not adopted by default.
Where a gateway earns its keep versus adds pure overhead
A single monolithic backend gains almost nothing from a gateway sitting in front of it — there's nothing to route between, and the extra network hop is pure latency with no compensating benefit. The pattern pays for itself once you have multiple independently deployed services that clients need to reach through one coherent surface, especially once authentication, rate limiting, or logging would otherwise need to be reimplemented in each service separately. Below that threshold, a gateway is complexity added for a problem that doesn't exist yet.
The failure mode: becoming a single point of failure
Routing every request for every service through one gateway process means that process's availability puts a ceiling on the availability of everything behind it — if the gateway goes down, clients can't reach any backend service, even the ones that are themselves perfectly healthy. This is why gateway deployments are typically run as a horizontally scaled, stateless fleet behind a load balancer rather than a single instance, and why gateway logic itself needs to stay lightweight: a slow regex-heavy routing rule or an expensive synchronous auth check in the gateway adds latency to literally every request in the system, not just the ones that happen to touch that particular concern.
Aggregation: sometimes the gateway does more than route
Some gateways go a step further and fan a single incoming request out to several backend services in parallel, then combine the results into one response — useful for a mobile client that wants one round trip instead of three. This blurs into what a GraphQL layer or a dedicated aggregation service does, and teams need to decide deliberately how much business logic belongs in the gateway versus in the services themselves; a gateway that accumulates too much orchestration logic stops being a thin routing layer and becomes a hard-to-test monolith wearing a gateway's name.
Versioning APIs through the gateway layer
Because every client request already passes through one place, the gateway is also a natural spot to handle API versioning — routing /v1/orders to an older service revision and /v2/orders to a newer one, or translating an older request shape into whatever the current backend actually expects, so backend teams can evolve a service's real interface without breaking clients still pinned to an old contract. This lets a backend team retire an old service version on its own schedule, once the gateway shows no meaningful traffic still hitting the old route, rather than needing every client to upgrade in lockstep on a fixed date.