Skip to content

Backend for Frontend (BFF)#

Problem statement (interviewer prompt)

A web app, iOS app, and partner API all need to render the same product page but with different field subsets, image sizes, and call patterns. A single one-size-fits-all backend ends up over-fetching for some and under-fetching for others. Design a layer that adapts the same backend services to each client.

The BFF pattern places one thin aggregation service per client type. Each BFF speaks the client's preferred shape (GraphQL for web, REST for mobile, gRPC for partners) and fans out to the same underlying microservices.

flowchart TB
  W([Web app]) --> BW[Web BFF]
  M([Mobile app]) --> BM[Mobile BFF]
  P([Partner API]) --> BP[Partner BFF]
  BW --> Cat[Catalog service]
  BW --> Inv[Inventory service]
  BW --> User[User service]
  BM --> Cat
  BM --> Inv
  BM --> User
  BP --> Cat
  BP --> Inv

    classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
    classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
    classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
    classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
    classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
    classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
    classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
    classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
    classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
    classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
    class W,M,P client;
    class BW,BM,BP edge;
    class Cat,Inv,User service;

Each BFF is owned by the client team; rendering churn doesn't propagate into the shared services.

Introduced by SoundCloud and popularised by Sam Newman; the BFF is the practical answer to "one backend, many very different clients."

The shape#

flowchart TB
  subgraph Clients
    W([Web SPA])
    M([Mobile])
    TV([TV])
    PA([Partner])
  end
  subgraph BFFs
    BW[Web BFF<br/>GraphQL or REST]
    BM[Mobile BFF<br/>compact REST]
    BT[TV BFF<br/>tile + carousel shape]
    BP[Partner BFF<br/>versioned REST + auth]
  end
  subgraph Domain[Domain services]
    Cat[Catalog]
    Order[Orders]
    User[Identity]
    Rec[Recommendations]
  end
  W --> BW
  M --> BM
  TV --> BT
  PA --> BP
  BW --> Cat
  BW --> Order
  BW --> User
  BW --> Rec
  BM --> Cat
  BM --> Order
  BT --> Cat
  BT --> Rec
  BP --> Cat

    classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
    classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
    classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
    classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
    classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
    classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
    classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
    classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
    classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
    classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
    class W,M,TV,PA client;
    class BW,BM,BT,BP edge;
    class Cat,Order,User,Rec service;

What lives in a BFF#

  • Aggregation: a single client call fans out to many backend calls in parallel.
  • Shape transformation: pick fields, rename, flatten, embed.
  • Authentication translation: external token (Google OAuth) → internal JWT (mTLS, signed identity).
  • Caching: per-client response cache; mobile gets longer TTL.
  • Light feature logic: A/B test routing, feature flag wiring, locale.
  • Throttling: per-client rate limits separate from backend limits.

What does NOT live in a BFF#

  • Business rules — they belong in the domain service.
  • Persistent state — BFF is stateless.
  • Cross-client logic — duplicate or push to a shared service.

BFF vs API gateway#

BFF API gateway
Specialised per client Yes No
Aggregates / shapes responses Yes Limited
Auth / rate limit Yes (per client) Yes (cross-cutting)
Generic policy enforcement No Yes
Common pattern Web + mobile + partner Multi-tenant API exposure

They compose: API gateway at the very edge → BFF per client → backend services.

flowchart LR
  Client --> GW[API gateway<br/>auth, rate limit, WAF]
  GW --> BFF[Client-specific BFF<br/>aggregate, shape]
  BFF --> Svc[Domain services]

    classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
    classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
    classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
    classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
    classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
    classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
    classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
    classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
    classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
    classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
    class Client client;
    class GW edge;
    class BFF,Svc service;

Ownership#

The client team owns its BFF. The cycle is: client devs add a field → push a BFF release → ship client → no backend service touched. Eliminates cross-team coordination on rendering churn.

When to skip BFF#

  • One client (web only): just expose a REST API.
  • Public API as product (Stripe, Twilio): the API IS the product.
  • GraphQL across the board: a federated GraphQL gateway can serve many shapes from one endpoint.

Pitfalls#

  • BFF turns into a god service: starts owning business rules. Refactor logic into backend services.
  • Duplicate logic across BFFs: extract into a shared library or a federated layer.
  • Over-fetching from backends: BFF must use efficient queries (GraphQL federation, gRPC streaming).
  • N+1 calls inside BFF: parallelise upstream fan-out with DataLoader-style batching.

How BFF composes#

flowchart TB
  BFF((BFF<br/>pattern))
  GW[API gateway<br/>at the edge]
  REST[REST API design<br/>typical wire format]
  GRPC[gRPC mechanics<br/>backend transport]
  CACHE[Caching strategies<br/>per-client response cache]
  GW --> BFF
  BFF --> REST
  BFF --> GRPC
  BFF --> CACHE

    classDef client fill:#dbeafe,stroke:#1e40af,stroke-width:1px,color:#0f172a;
    classDef edge fill:#cffafe,stroke:#0e7490,stroke-width:1px,color:#0f172a;
    classDef service fill:#fef3c7,stroke:#92400e,stroke-width:1px,color:#0f172a;
    classDef datastore fill:#fee2e2,stroke:#991b1b,stroke-width:1px,color:#0f172a;
    classDef cache fill:#fed7aa,stroke:#9a3412,stroke-width:1px,color:#0f172a;
    classDef queue fill:#ede9fe,stroke:#5b21b6,stroke-width:1px,color:#0f172a;
    classDef compute fill:#d1fae5,stroke:#065f46,stroke-width:1px,color:#0f172a;
    classDef storage fill:#e5e7eb,stroke:#374151,stroke-width:1px,color:#0f172a;
    classDef external fill:#fce7f3,stroke:#9d174d,stroke-width:1px,color:#0f172a;
    classDef obs fill:#f3e8ff,stroke:#6b21a8,stroke-width:1px,color:#0f172a;
    class BFF service;
    class GW,REST,GRPC,CACHE datastore;

Glossary & fundamentals#

Tag Concept What it is Page
HLD API Gateway edge layer in front of BFF api-gateway
LLD REST API design typical BFF wire format rest-api-design
HLD gRPC mechanics backend transport for BFF grpc-mechanics
HLD Caching strategies per-client response cache caching-strategies

Quick reference#

Idea#

One thin aggregation service per client type (web / mobile / TV / partner). Each BFF fans out to the same domain services and serves the client its preferred shape.

What BFF does#

  • Fan out to backends in parallel
  • Shape / project / rename
  • Translate auth (OAuth → internal JWT)
  • Per-client cache + rate limit
  • Light feature flag / A/B routing

What it does NOT do#

  • Business rules (live in domain)
  • Persistent state
  • Cross-client logic

BFF vs API gateway#

BFF Gateway
Per client Yes No
Aggregate Yes Limited
Cross-cutting (WAF, rate) Partial Yes

Compose: client → API gateway → BFF → services.

Ownership#

Client team owns its BFF; backend churn doesn't block client launches.

Skip BFF when#

  • Single client app
  • Public API as product
  • Federated GraphQL serves all shapes

Pitfalls#

  • BFF turning into god service
  • Duplicate logic across BFFs
  • N+1 fan-out (use DataLoader batching)

Refs#

  • Sam Newman - BFF pattern
  • SoundCloud BFF post
  • Microsoft architecture docs

FAQ#

What is the Backend for Frontend pattern?#

BFF places a thin per-client aggregation service in front of shared backend microservices. Each BFF tailors data shape, payload size, and call patterns to one client like web, iOS, or partners.

BFF pattern vs API gateway, what is the difference?#

An API gateway is shared across many clients and focuses on auth, routing, and rate limiting. A BFF is per-client and contains business aggregation logic specific to that client's screens.

When should I use the BFF pattern?#

Use BFF when multiple clients need different views of the same backend services, or when mobile and web require different payload sizes and call patterns. Skip it for simple single-client products.

Who owns the BFF code?#

Best practice is that the frontend team owns its BFF so they can move at frontend speed without backend coordination. The BFF acts as their personal backend, not a shared platform.

Does GraphQL replace BFF?#

GraphQL solves over-fetching and under-fetching at the protocol level, often used to implement a BFF. You still need per-client business logic, so the BFF concept survives even when the transport is GraphQL.

Further reading#