Architecture Patterns

Backends for Frontends (BFF)

18 min Lesson 7 of 10

Backends for Frontends (BFF)

As product teams ship across web, mobile, and third-party integrations simultaneously, a single general-purpose API begins to crack under the weight of contradictory demands. The mobile app needs lean, battery-conscious payloads; the browser dashboard wants rich, aggregated data in one round-trip; the public partner API demands strict versioning and coarse-grained resources. Trying to satisfy all three from one backend leads to the worst of all worlds: an API cluttered with ?fields= query knobs, version negotiation, and platform-specific hacks baked into shared code.

The Backends for Frontends (BFF) pattern — popularized by Sam Newman at SoundCloud and later documented as a formal pattern — resolves this tension by giving each distinct client type its own thin backend layer, purpose-built for that surface.

What Is a BFF?

A BFF is a server-side component that sits between a specific client (Web, iOS, Android, smart TV, partner API) and the downstream microservices or domain APIs. It speaks the client's language: it knows exactly what data the screen needs, in what shape, at what granularity. It aggregates calls to multiple services, transforms payloads, enforces client-specific auth flows, and hides downstream complexity.

Crucially, the BFF is owned by the same team that owns the client. The iOS team owns the iOS BFF. This eliminates the coordination overhead of asking a shared API team to add a mobile-specific endpoint — the mobile team ships it themselves.

BFF pattern — each client type gets its own dedicated backend Web App Browser Mobile App iOS / Android Partner API 3rd Party Web BFF GraphQL / REST Aggregates + SSR data Mobile BFF REST / Protocol Buf Lean payloads, push Partner BFF REST (versioned) OAuth2, rate limits User Service profiles, prefs Order Service cart, checkout Product Service catalog, pricing Notification Svc push, email, SMS Ownership Web BFF ← Frontend Team Mobile BFF ← Mobile Team Partner BFF ← Platform Team Each team deploys independently
BFF pattern: three client types, three purpose-built backends, all calling the same shared downstream services.

The Problem a Single API Creates

Without BFF, a single shared backend has to accommodate every client simultaneously. This creates several well-known failure modes:

  • Over-fetching. The desktop dashboard wants 40 fields per product. The mobile card only needs 5. The shared endpoint returns 40, so every mobile request carries 35 fields of wasted bytes. On a slow 3G connection with 100 items in a list, that overhead adds hundreds of milliseconds and burns battery.
  • Under-fetching. The mobile homescreen needs data from User, Order, and Product services in one render. A shared REST API that mirrors service boundaries forces the client to make three separate requests. On mobile, each round-trip adds 100–300 ms of latency.
  • Coupling and fear of change. When dozens of clients depend on one API, every change risks breaking someone. The team ends up paralyzed, adding optional fields and perpetuating old endpoints forever (/v1, /v2, /v3…).
  • Auth and session complexity. Cookie-based sessions work for browsers but are wrong for mobile apps. JWTs are appropriate for mobile but undesirable in browsers because of XSS risk. A single endpoint cannot be optimal for both without branching logic.
SoundCloud's origin story: Sam Newman coined the BFF pattern while at SoundCloud around 2015. SoundCloud had a single API team gatekeeping all backend access. Every time the iOS or Android team wanted a new endpoint, they opened a ticket and waited. Adding a dedicated mobile BFF — owned by the mobile team — broke that bottleneck and cut time-to-feature by weeks.

What Belongs in a BFF

A BFF is deliberately thin. Its responsibilities are:

  1. Aggregation. Fan out to N downstream services in parallel, then stitch the responses into a single client-optimised payload.
  2. Transformation. Rename fields, flatten nested structures, convert units, and apply client-specific formatting (date formats, currency symbols, image sizes).
  3. Auth adaptation. Exchange tokens, implement the right session strategy for that client (cookies for web, short-lived JWTs for mobile, API keys for partners), and forward the correct identity downstream.
  4. Caching at the right layer. A web BFF can cache aggregated responses in Redis keyed by user + page, slashing repeated downstream calls for the same dashboard view.
  5. Feature flags and A/B logic. Serve different response shapes based on experiment assignment — without polluting downstream services with UI experiment logic.

What a BFF should not contain: core business logic, database writes, domain validation. Those belong in the downstream services. The moment a BFF starts doing domain work, it becomes a service in its own right and should be renamed accordingly.

Mobile BFF request flow — fan-out aggregation and payload trimming Mobile App 1 request GET /home Mobile BFF 1. Auth check 2. Fan-out (parallel) 3. Trim + reshape 4. Return 5 fields ~25ms total parallel User Service 40 fields returned Order Service 20 fields returned Product Service 35 fields returned 5 fields Payload savings 95 fields received total 5 fields sent to client ~95% bandwidth reduction
Mobile BFF fans out to three services in parallel, trims 95 fields down to 5, and returns one lean response to the app.

BFF vs. API Gateway

Students often confuse the BFF with an API Gateway. They are different tools with different jobs:

  • An API Gateway is infrastructure: it handles cross-cutting concerns for all traffic — TLS termination, rate limiting, JWT verification, routing. It is client-agnostic and owned by the platform team.
  • A BFF is a product concern: it knows the data model, the screen layout, and the interaction patterns of one specific client. It is owned by the product team that owns the client.

In most architectures they coexist. Requests flow: Client → API Gateway (infra) → BFF (product) → Downstream Services. The Gateway handles auth tokens and rate limiting; the BFF handles aggregation and reshaping.

Trade-offs and When Not to Use BFF

BFF is not free. The honest trade-offs are:

  • Code duplication. Three BFFs often contain similar aggregation logic. If you have a small team, this duplication can outweigh the benefit. Use a shared library or move common logic to downstream services.
  • One more hop. Every request now has an extra network call. At low latency (co-located services on the same internal network) this is typically under 1 ms — acceptable. But it is a cost.
  • More moving parts to operate. Three BFFs means three services to monitor, deploy, and scale. For a team of 3 engineers, a single API with a few client-specific endpoints is likely the right call.
Start with one BFF, not three. If you have a web app today and might build mobile later, start with a single BFF. When the mobile team forms and their needs diverge significantly, split it. The pattern does not mandate a 1:1 ratio from day one — it mandates intentional client-to-backend alignment.
The "fat BFF" anti-pattern. Teams that let business logic creep into the BFF end up with the worst of both worlds: a tightly-coupled layer that is hard to test, hard to reuse, and impossible to share. Enforce a hard rule: the BFF transforms and aggregates; it never validates domain invariants or writes to a database directly.

Real-World Adoption

BFF is now standard practice at companies operating multi-surface products. Netflix uses a BFF-like "edge API" layer (Falcor/GraphQL) that tailors responses for the TV app, mobile app, and web player. Spotify maintains separate gateway layers per client surface. Zalando built one of the most cited public BFF implementations, documenting how their web and mobile BFFs each aggregate from 50+ microservices. The pattern is also a natural fit for GraphQL: the BFF becomes a GraphQL server that resolves fields by calling downstream REST services, giving the client precise control over the shape of data it receives.

Summary

The BFF pattern addresses a fundamental tension in multi-surface product development: different clients have radically different data needs, and a single shared API cannot serve them all optimally. By giving each client type a thin, purpose-built backend owned by the same team, you eliminate over-fetching, under-fetching, and the fear-of-change that paralyzes shared API teams. The cost is additional services to operate — a trade-off that pays off as soon as client surfaces diverge meaningfully.