Backend for Frontend (BFF) Pattern: Tailored APIs per Client, Visualized
A Backend for Frontend (BFF) is a dedicated backend service built for one specific frontend β web, mobile, or IoT β that aggregates and shapes data from downstream microservices so each client gets exactly the payload it needs. This guide covers why one generic API hurts diverse clients, request aggregation, payload shaping, and how BFFs relate to API gateways β with live animations.
The Backend for Frontend (BFF) pattern is an architecture in which you build a separate, dedicated backend service for each type of frontend β one for web, one for mobile, one for IoT β instead of forcing every client to share a single general-purpose API. Each BFF sits between its client and the downstream microservices, aggregating and reshaping data so the frontend receives exactly the payload it needs and nothing it doesn't.
In a microservices system, the data a screen needs is rarely owned by a single service. A product page might pull from a catalog service, a pricing service, a reviews service, and an inventory service. The question is who stitches those calls together. The BFF pattern answers: a thin server-side layer owned by the frontend team, tuned to one client's exact requirements.
Why One Generic API Hurts Diverse Clients
A single shared API has to be a compromise. A desktop web client on fibre can happily render a fat JSON blob with fifty fields and nested relationships. A mobile client on a flaky cellular connection wants a slim payload, fewer round trips, and battery-friendly behaviour. An IoT device or smart TV might only need three fields and can barely parse a large response at all. When one API serves all of them, it ends up over-serving the constrained clients and under-serving the rich ones.
The friction is real: every time the mobile team needs a field trimmed or two calls merged, they have to negotiate with whoever owns the shared API β a team juggling the needs of every other client at once. Versioning becomes painful, because a change for mobile risks breaking web. The shared API slowly accretes client-specific flags and query parameters until it serves everyone badly. A BFF cuts that knot by giving each frontend a backend it fully controls.
A Dedicated BFF per Client Type
The core move is one BFF per experience, not per microservice. The web app talks only to the Web BFF; the mobile app talks only to the Mobile BFF; an IoT or TV experience gets its own. Each BFF is free to expose whatever shape, endpoints, and protocol best suit its client, while the downstream microservices stay generic and stable. The animation below shows three clients each hitting their own BFF, which fans out to the same shared microservices and returns a tailored response.
Request Aggregation and Composition
Without a BFF, a client often has to make many calls to render one screen β fetch the product, then its price, then its reviews, then stock β each a separate round trip over a high-latency mobile link. This is the chatty client problem. A BFF performs request aggregation: the client makes one call, and the BFF fans out to the downstream services in parallel, waits for them, and composes a single response. Round trips over the slow network drop from many to one.
Aggregation in a BFF is usually just parallel fan-out with a join. A small Node.js handler makes that concrete:
// Web BFF: one endpoint, parallel fan-out, composed response
app.get('/bff/product/:id', async (req, res) => {
const id = req.params.id;
const [product, price, reviews, stock] = await Promise.all([
catalog.get(`/products/${id}`),
pricing.get(`/price/${id}`),
reviews.get(`/reviews/${id}?limit=3`),
inventory.get(`/stock/${id}`),
]);
// Compose + shape for THIS client
res.json({
id: product.id,
title: product.title,
price: price.amount,
currency: price.currency,
inStock: stock.available > 0,
topReviews: reviews.items.map(r => ({ stars: r.rating, text: r.body })),
});
});Payload Shaping and Trimming
Aggregation merges calls; payload shaping decides what comes back. A microservice's natural response is verbose β internal IDs, audit timestamps, nested objects, fields no UI renders. The BFF projects that down to precisely what one screen needs. The Mobile BFF might return six fields where the Web BFF returns thirty. It can rename fields to match the client's models, flatten nested structures, pre-format dates and currency, and drop everything irrelevant β shrinking bytes on the wire and CPU spent parsing on a constrained device.
Moving Orchestration Off the Client
When the client orchestrates β calling service A, using its result to call B, retrying C, handling partial failures β that logic gets duplicated across iOS, Android, and web, and it ships inside an app you can't easily update once it's on a user's phone. A BFF pulls orchestration to the server. Call sequencing, retries, timeouts, fallbacks, and the "if reviews fail, render the page anyway" rules live in one deployable service that you can fix without an app-store release. The client becomes a thin renderer of whatever the BFF returns.
BFF vs API Gateway
BFFs and API gateways are often confused because both sit between clients and microservices. An API gateway is a single, generic entry point handling cross-cutting concerns β authentication, rate limiting, TLS termination, routing β the same way for everyone. A BFF is client-specific: it knows about screens and use cases and exists to aggregate and shape data for one frontend. They are complementary. A common topology is a shared gateway in front of several BFFs: the gateway does auth and rate limiting, then routes to the Web BFF or Mobile BFF, each of which composes its own tailored response.
| API Gateway | BFF | |
|---|---|---|
| Purpose | Generic entry point for all clients | Tailored backend for one client type |
| Count | Usually one per system | One per frontend (web, mobile, IoT) |
| Owned by | Platform / infra team | The frontend team it serves |
| Main concerns | Auth, rate limit, routing, TLS | Aggregation, payload shaping, orchestration |
| Knows about UI? | No β client-agnostic | Yes β built around screens |
Generic Shared API vs BFF
| Aspect | Generic shared API | Backend for Frontend |
|---|---|---|
| Payload | One-size compromise for all clients | Shaped exactly for one client |
| Round trips | Client makes many calls | One aggregated call per screen |
| Change velocity | Cross-team negotiation, shared versioning | Frontend team ships independently |
| Orchestration | Often on the client | On the server, in the BFF |
Downsides and When to Skip It
BFFs are not free. Code duplication is the headline cost β the Web and Mobile BFFs often need similar aggregation logic, and naive copy-paste drifts out of sync; teams usually extract shared pieces into libraries while keeping the client-specific shaping separate. You also have more services to deploy, monitor, secure, and keep available, and each BFF is another network hop and another potential point of failure. For a small team with a single client, or an internal tool, a BFF is over-engineering β the pattern earns its keep once you have multiple genuinely different frontends over a fan-out of microservices.
Who Uses It
The pattern was popularized at SoundCloud β the term "Backend for Frontend" is widely credited to Phil CalΓ§ado and the SoundCloud team as they broke up a monolith and needed per-client edge services. Netflix independently pushed a similar idea hard, building device-specific adapters at the edge so hundreds of device types β phones, TVs, consoles, browsers β each get a response tuned to their constraints rather than one universal API. Today BFFs are standard practice across companies running rich microservice backends behind multiple distinct frontends.
Frequently Asked Questions
Is a BFF the same as an API gateway?
No. An API gateway is a single generic entry point that handles cross-cutting concerns like auth and rate limiting uniformly for every client. A BFF is client-specific and exists to aggregate and shape data for one frontend. They're complementary β a gateway often sits in front of several BFFs, doing auth and routing before each BFF composes its tailored response.
How many BFFs should I have?
One per distinct frontend experience, not one per microservice. Typically that means a Web BFF, a Mobile BFF, and perhaps an IoT or partner BFF. If two clients have nearly identical needs, share a single BFF β don't split until their requirements actually diverge, since each BFF adds deployment and maintenance overhead.
Does a BFF replace GraphQL?
They overlap but aren't identical. GraphQL lets the client select fields and aggregate across resolvers, solving over-fetching and chatty calls from the client side. A BFF solves the same problems server-side with full freedom over protocol, caching, and orchestration. Many teams combine them β a per-client GraphQL endpoint is effectively a BFF whose query language is GraphQL.
A BFF gives every frontend the API it wishes it had: one call, exactly the right fields, and all the orchestration moved to a server you can actually deploy.
β alokknight Engineering
