What Is a BFF? Why Your Mobile App Deserves Its Own API
For: A product-focused CTO at a Series A SaaS startup whose mobile and web apps both consume the same general-purpose API — and whose mobile engineers are constantly complaining about over-fetching, sluggish screens, and having to make four round-trips to render one page
A Backend for Frontend (BFF) is a thin server layer that sits between one specific client — your iOS app, your web dashboard, your Apple Watch companion — and your downstream services. Each client gets its own BFF, owned by the team building that client. It exists so mobile engineers stop begging the central API team for a tailored endpoint and start shipping one themselves. The performance win is real but secondary; the actual prize is removing the coordination tax between your client teams and your backend team.
If your mobile engineers are complaining about over-fetching and four round-trips per screen, the fix probably isn't GraphQL or better REST design. It's a boundary change.
The problem a BFF actually solves
One general-purpose API serving web, iOS, and Android sounds efficient. It rarely is. Here's what usually happens at Series A scale:
- The web dashboard needs a fat
/userresponse with billing, org, and feature flags. Mobile only needs the user's display name and avatar — but gets the whole payload anyway. - The mobile home screen needs data from three services. Because the API mirrors the service boundaries, the app fires three requests and stitches them client-side. On a spotty 4G connection, that's your P95 latency problem.
- Every change to the shared API requires the mobile team to file a ticket with backend, wait behind web's requests, negotiate a shape that doesn't break other clients, and then coordinate a release.
The over-fetching is annoying. The round-trips are annoying. But the real cost is that third one: your mobile team can't ship without someone else's roadmap agreeing. That's the coordination tax, and it dwarfs any 200ms you'd save with a smarter payload.
The analogy: a personal shopper vs. a warehouse
Your downstream services are a warehouse. Everything is in there, organized by category, in bulk. A general-purpose API is a self-service checkout: any customer can go grab what they need, but they have to walk every aisle themselves and carry it all home.
A BFF is a personal shopper who works for one specific customer. Your mobile app tells the shopper, "I need the home screen." The shopper walks the warehouse, grabs exactly the right items from three different aisles, throws away the packaging, and hands over a single neatly-wrapped bag. The mobile app didn't need to know the warehouse layout. It didn't need to make three trips. And crucially, the shopper reports to the mobile team — not to warehouse management.
A minimal worked example
Say your SaaS has three backend services: users, projects, and notifications. Your mobile home screen shows: the user's name, their three most recent projects, and an unread notification count.
Without a BFF, the mobile app does:
GET /api/users/me → 4KB response, uses 200 bytes
GET /api/projects?user=me&limit=3 → 8KB response, uses 1KB
GET /api/notifications/unread-count → 1KB response, uses 20 bytes
Three round-trips. ~13KB over the wire. Client code has to orchestrate, handle partial failures, and reshape the data.
With a mobile BFF, the app does:
GET /mobile/home
// response — ~500 bytes
{
"greeting": "Priya",
"recentProjects": [
{ "id": "p_1", "name": "Q4 launch", "lastEdited": "2h ago" },
...
],
"unreadCount": 7
}
The BFF — a small Node or Go service owned by the mobile team — makes the three internal calls in parallel, formats lastEdited as a human string (not an ISO timestamp the client has to parse), and returns exactly what the screen needs. One round-trip. 500 bytes. No client-side orchestration.
The important part: when the design team decides the home screen should now show the user's team name, the mobile team edits their BFF and ships. They don't file a ticket with backend.
Gotchas nobody warns you about
1. You will duplicate code across BFFs
Your iOS BFF and Android BFF will look 90% identical. Resist the urge to merge them into a "mobile BFF" unless the two apps really do have identical needs — which they usually don't for long. Duplication across BFFs is fine. Sharing them creates the same coordination problem you were trying to escape.
2. BFFs are not a place for business logic
A BFF aggregates, filters, and reshapes. It does not decide whether a user can access a project. That belongs in the domain service. If your BFF starts holding auth rules or pricing logic, you've built a distributed monolith and every client team now owns a slice of your core business rules. Keep BFFs boring.
3. Someone has to own the downstream contracts
BFFs decouple clients from services, but the services still need clean, versioned APIs. If your backend team responds to BFFs by saying "great, now we don't need contracts," you've made things worse. The BFF pattern assumes downstream services expose stable, well-designed internal APIs — usually gRPC or REST with strong typing.
4. You've added another deploy target
Each BFF is a service you have to deploy, monitor, and page someone about at 3am. For a two-person mobile team, that overhead is real. Do not adopt BFFs until the coordination pain clearly exceeds the ops pain.
5. GraphQL is not a substitute — but it can be a BFF
Teams often ask: "Can't we just put GraphQL in front of the services and skip the BFF?" You can, and a shared GraphQL gateway solves the over-fetching problem. It does not solve the ownership problem. If the GraphQL schema is owned by the backend team, your mobile engineers are still queuing for changes. GraphQL is a query language; BFF is an org pattern. They compose well — you can absolutely have a mobile BFF that speaks GraphQL — but one is not a replacement for the other.
When to use a BFF — and when not to
Use a BFF when:
- You have two or more meaningfully different client surfaces (mobile + web is the classic pair; add a smart-TV app or a partner embed and the case gets stronger).
- Client teams are blocked waiting for backend API changes more than once a sprint.
- Mobile P95 latency is dominated by round-trips or payload size, not by downstream service performance.
- You have — or are about to have — enough microservices that no single API can cleanly serve everyone.
Skip the BFF when:
- You have one client (say, just a web app). A BFF is just a weird extra layer. Put the aggregation logic in your regular API.
- Your team is under ten engineers total. The coordination tax barely exists yet. A well-designed REST or GraphQL API will carry you further than you'd expect.
- Your downstream services are still a monolith. There's nothing to aggregate. Fix the API first.
The org-chart test
Here's the diagnostic I'd run before writing a line of BFF code: look at your last twenty mobile bug fixes and feature launches. How many required a backend API change? Of those, how many were delayed because backend had other priorities? If that number is meaningful, you have an organizational problem, and restructuring the API layer to match team boundaries — which is what the BFF pattern really is — will help. If the number is near zero, your API is fine. Fix something else.
The architecture patterns worth adopting are the ones that let independent teams ship independently. BFF is one of them. GraphQL federation is another. Event-driven services are a third. They're not competitors — they're tools you reach for depending on which coordination problem is biting you today.
Frequently Asked Questions
Is the BFF pattern the same as an API gateway?
No. An API gateway is one shared entry point that handles cross-cutting concerns — auth, rate limiting, routing — for all clients. A BFF is a per-client server that shapes responses for one specific frontend. You often have both: a gateway sits at the edge, and BFFs sit behind it, one per client surface.
Should each mobile platform (iOS and Android) have its own BFF?
Usually yes, especially once the two apps diverge in features or navigation. Start with one "mobile" BFF if the apps are genuinely identical, but split as soon as one platform ships something the other doesn't. Sharing a BFF across teams recreates the coordination problem the pattern is meant to solve.
Can we build a BFF with GraphQL instead of REST?
Absolutely. A GraphQL BFF is a common and effective combination — you get the tailored aggregation of a BFF plus the flexibility of client-driven queries. Just make sure the schema is owned by the client team, not the backend team, or you've lost the org-boundary benefit.
What language should we write our BFF in?
Whatever language the client team is most productive in. Node and TypeScript are common because web and mobile engineers can read them; Go is popular where teams want faster cold starts and simpler ops. The point of a BFF is that the team owning the client also owns the BFF — so optimize for their velocity, not for consistency with the backend stack.
How do we migrate an existing shared API to a BFF architecture?
Strangle it. Stand up a BFF for one client — usually mobile, since that's where the pain is loudest — and route one screen through it. Prove the pattern, then migrate screen by screen. Don't rewrite the shared API; let it stay as the internal service layer the BFFs call. For a hands-on assessment of your specific architecture, contact CodeNicely for a personalized review.
Found this useful? CodeNicely publishes engineering and product playbooks weekly. Browse the archive or tell us what you're building.
_1751731246795-BygAaJJK.png)