I once watched a mobile app fire nine separate requests just to render a single home screen. The API had actually been designed for web; mobile was collecting the data the way web sliced it, piece by piece, and stitching it back together on screen. Nine round-trips per launch — over mobile network conditions, no less.

That was the bill for the “one API fits everyone” assumption. The BFF — Backend for Frontend — exists precisely to cancel that bill.

What a BFF is

A BFF is a thin API layer tailored to one specific client type. Web gets its own BFF, mobile gets its own. Each one calls the same underlying services and domain, but shapes the response to fit its own client’s screen.

The real business logic doesn’t live in the BFF. The BFF is only an adaptation layer: it aggregates, trims unneeded fields, and gathers everything a client needs for one screen into a single response.

The hidden cost of bending one API to fit everyone

A single general-purpose API can’t fully satisfy two clients over time:

  • Over-fetching. Mobile downloads a 40-field user object and uses 4 of them. The rest is wasted bandwidth and battery.
  • Chatty flow. The “fetch the list first, then fetch details for each row” flow that web finds perfectly normal turns into nine round-trips on a mobile network.
  • Conditional fields. The response starts branching with if mobile then ... else .... A single endpoint tries to carry the requirements of two clients at once and does a mediocre job for both.
  • Versioning knot. A change needed for web risks breaking mobile’s published version. Two clients get locked into one contract.

Each of these costs looks small on its own; their sum is an architectural problem.

When a BFF is warranted

A BFF is justified when client needs genuinely diverge:

  • Mobile and web need distinctly different screens and different data shapes.
  • Mobile network and battery constraints make round-trip count and payload size a first-class concern.
  • The clients ship at different cadences — the mobile release is stuck in store review while web deploys every day; a single contract locks the two together.

When these differences exist, giving each client its own BFF is cheaper than constantly bending one API to fit both.

When a BFF is unnecessary

If you have a single client, a BFF adds more layer than it solves — just an extra hop.

If you have two clients but both want almost the same data in almost the same shape, it’s still unnecessary. What justifies a BFF isn’t the number of clients but the difference between them. No difference, no separate layer — otherwise it’s speculative generality in the shape of an API layer.

A BFF is not a microservice

A common confusion: adding a BFF doesn’t drop you into distributed architecture. A BFF is a presentation/aggregation layer, not a domain service. Putting business rules inside it means copying the rule once per client.

The BFF’s only kinship with microservices is this: both ask “is this worth a separate deployable?” The answer is usually “no” — the measured-signal threshold from the decision to move to microservices applies here too.

Start light

“BFF” doesn’t have to mean standing up a separate server. Within the same monolith:

  • One route namespace per client — routes/web-api.php, routes/mobile-api.php — each with its own controllers and its own response shape.
  • Or a single GraphQL layer: each client queries exactly what it needs, and over-fetching resolves itself.

The real idea isn’t a box, it’s a boundary: collect the client-specific adaptation in one place and keep the domain clean of it. Move to a separate deployable only when a measured signal forces it.


The BFF is the antidote to the “every client makes do with the same API” stubbornness — but only when clients genuinely diverge. No difference, no layer.

What adds the layer isn’t the number of clients, it’s the distance between them.