The problem
With 40 services, clients shouldn't know 40 hostnames, and each service shouldn't re-implement auth, rate limiting, CORS and logging. Mobile also wants small payloads, while the web dashboard wants rich aggregates.
How it works
Gateway responsibilities: routing, TLS termination, authentication (validate the JWT once), rate limiting and quotas, request/response logging, CORS, caching, and API versioning.
BFF responsibilities: aggregate several service calls into one screen-shaped response, trim payloads for mobile, and handle client-specific auth flows.
Rules of thumb
- No business logic in the gateway. It becomes a distributed monolith fast.
- Pass identity downstream (a signed JWT or internal headers). Services still authorise.
- The gateway is a single point of failure, so run it HA with sensible timeouts.
- One BFF per experience, owned by the frontend team, not one per device model.
- Multiple services behind one public API
- Different client types need different shapes
- Centralised auth, quotas and observability at the edge
- A single backend — a reverse proxy is enough
- Teams start pushing domain logic into the gateway
Cheatsheets
The whole topic on one page. Click to open full screen.
Sources & further learning
Videos, courses, docs and books I recommend for this topic.
Related topics
Microservices Architecture
Structure a system as independently deployable services, each owning a business capability and its data, communicating over the network.
Design: Distributed Rate Limiter
Protect APIs and tenants — algorithms (token bucket, sliding window), distributed counters in Redis, and where to enforce limits.
Circuit Breaker, Retry, Timeout & Bulkhead
The resilience toolkit — fail fast, retry safely, bound waiting, and isolate resources so one slow dependency can't take down the whole system.
Sidecar & Service Mesh
Move networking concerns — mTLS, retries, traffic splitting, telemetry — out of application code into a proxy deployed next to every service.