How the Backend for Frontend pattern creates purpose-built API layers for each client type, eliminating over-fetching and moving aggregation logic out of the client.
28 min read2026-04-04mediumpatternsapi-designmicroservicesarchitecture
A Backend for Frontend (BFF) is a thin, purpose-built API layer that sits between a specific client type and your backend microservices, returning exactly the data shape that client needs.
BFF eliminates over-fetching for mobile and under-fetching for web by letting each client team own its own backend aggregation layer.
BFF is not an API gateway. The gateway handles infrastructure (auth, rate limiting, routing). The BFF handles business logic (aggregation, response shaping, client-specific orchestration).
The frontend team owns the BFF, not the backend team. This is the key organizational insight.
When a single GraphQL endpoint can serve all clients well, you may not need separate BFFs at all.
You have a mobile app and a web app. They call the same backend APIs. The web dashboard needs a full user profile with activity history, recent orders, and product recommendations, all aggregated from five microservices. The mobile home screen needs an avatar, a username, and a recent order count.
One generic API serves both. The mobile client downloads 10x more data than it displays, burning bandwidth and battery. The web client makes six sequential API calls to assemble a single page, adding 400ms of round-trip overhead. The frontend team ends up writing aggregation logic in JavaScript, merging responses from multiple services on the client side.
Now your "thin client" is doing backend work. Every new screen needs coordination across services. The iOS team and the web team both write the same aggregation code, differently, with different bugs. I've seen this pattern turn a 2-week feature into a 6-week multi-team coordination nightmare.
The fix is not "make the API return less." The fix is giving each client type its own purpose-built backend layer.
Continue Reading with Premium
Unlock this article and every other in-depth system design guide on the platform with NotesFromSDE Premium.
A Backend for Frontend creates a dedicated server-side layer per client type that aggregates, transforms, and shapes microservice responses into exactly what that client needs.
Think of a restaurant with a diverse customer base: a diner ordering a full meal, someone grabbing takeout, and a delivery driver. The kitchen (microservices) makes the same food. But the diner gets it on plates with cutlery. Takeout gets it boxed with napkins and utensils. Delivery gets it sealed in bags with order slips.
The kitchen doesn't change. The packaging changes per consumer. The BFF is the packaging station, not the kitchen.
The BFF sits between the client and the microservices. Each client type gets its own BFF, and each BFF calls the same underlying services but returns a different response shape.
The Web BFF aggregates data from all three services into a single rich response for the dashboard. It calls User, Product, and Order services in parallel, merges the results, and returns a composite JSON payload. The mobile BFF calls only User and Order, returns five fields, and omits product recommendations entirely.
Here's how the mobile BFF handles a home screen request:
The client gets a 200-byte response instead of 5KB. The BFF strips 95% of the payload. On a 3G connection, that is the difference between a 100ms load and a 2-second load.
This distinction trips people up. Here is the clean separation:
Concern
API Gateway
BFF
Authentication
β Token validation, OAuth
β Not its job
Rate limiting
β Per-client throttling
β Not its job
SSL termination
β
β
Request routing
β Routes to correct BFF
β
Response shaping
β Passes through
β Transforms and aggregates
Business logic
β Zero business logic
β Client-specific logic
Owned by
Platform/infra team
Frontend team
The gateway is infrastructure. The BFF is product logic. They sit at different layers and are owned by different teams. For your interview: if someone asks "why not just use an API gateway," the answer is that gateways don't aggregate or transform, they route.
This is the organizational insight that makes BFF work. The frontend team owns the BFF, not the backend team. The iOS team owns the Mobile BFF. The web team owns the Web BFF.
Why? Because the frontend team knows what data each screen needs. They know when the design changes. They know when a field is added or removed. If the backend team owns the BFF, every screen change requires a cross-team ticket, and you are back to the coordination problem BFF was supposed to eliminate.
My recommendation: if you cannot give BFF ownership to the frontend team, do not adopt the pattern. A BFF owned by the backend team becomes just another generic API layer.
// Mobile BFF - Express.js handler for /homeapp.get('/home', async (req, res) => { const userId = req.auth.userId; // Parallel calls to backend services const [user, orders] = await Promise.all([ userService.getUser(userId), orderService.getRecentOrders(userId, { limit: 3 }), ]); // Shape response for mobile - only what the screen needs res.json({ avatar: user.avatarUrl, firstName: user.name.split(' ')[0], recentOrders: orders.map(o => ({ id: o.id, status: o.status, })), });});
The BFF is intentionally thin. No database of its own, no persistent state. It is a translator and aggregator. If your BFF starts growing its own data model, that is a smell.
Multiple client types with wildly different data needs. Web dashboard vs mobile app vs IoT sensor.
Frontend teams that ship independently. The iOS team can update their BFF without waiting on backend changes.
High-latency clients (mobile, IoT). A single BFF call replaces multiple round trips. On a 500ms-RTT cellular connection, going from 6 calls to 1 saves 2.5 seconds.
Legacy backend with chatty APIs. The BFF shields clients from needing 14 calls to build a single screen.
Different auth flows per client. Web uses cookie sessions, mobile uses refresh tokens, TV uses device pairing codes. Each BFF handles its own auth concern.
You start with Web BFF and Mobile BFF. Then someone adds Tablet BFF, Watch BFF, Partner BFF, Internal-Tool BFF. Each needs maintenance, deployment pipelines, and monitoring. The rule of thumb: one BFF per experience, not per device. A tablet that shows the same screens as the web app uses the Web BFF.
The BFF accumulates business rules, validation, caching, and eventually its own database. Now you have a second monolith sitting between clients and services. Keep BFFs stateless. If logic belongs in a service, push it down.