الدرس 1 من 2
Why a Shared API Fails Several Clients
A single general-purpose API serving a web app, a mobile app and a partner integration ends up serving none of them well. A BFF is a per-experience answer.
Once a system is several services, a client needs somewhere to talk to. The natural first answer is one API for everyone. It works while there is one client. It comes under pressure as soon as there are two with genuinely different needs, and the pressure is structural rather than a failure of API design.
| Client | Wants | Suffers from a shared API |
|---|---|---|
| Mobile app | Few round trips, small payloads, aggressive aggregation | Over-fetching on a metered network; six calls to render one screen |
| Web app | Rich data, rapid iteration alongside the frontend | Waiting on an API team's release cycle for a field |
| Partner integration | Stability, versioning, formal deprecation | Breaking changes driven by internal client needs |
Shared API versus a backend per experience
The BFFs are thin. All the business logic remains in the services behind them.
On the left, three clients all call one shared API which calls four services. On the right, each client calls its own backend for frontend, and each of those calls whichever of the four services it needs. The partner integration keeps a formally versioned API of its own.
Clients
Mobile app
Web app
Partner systems
Per-experience backends
Mobile BFF
owned by the mobile team
Web BFF
owned by the web team
Public API
versioned, conservative
Domain services
Catalogue
Ordering
Identity
Billing
// mobile-bff: one request, one screen, exactly the fields it renders.
export async function GET(request: Request) {
const principal = await authenticate(request); // identity comes from the edge
const [enrolment, nextLesson, streak] = await Promise.all([
learning.enrolmentSummary(principal.id),
learning.nextLesson(principal.id),
progress.streak(principal.id),
]);
// Shaping for one screen. The decision about *what a streak is* lives in
// the progress service; the BFF only decides what this screen displays.
return Response.json({
courseTitle: enrolment.courseTitle,
percentComplete: enrolment.percentComplete,
nextLesson: nextLesson && { slug: nextLesson.slug, title: nextLesson.title },
streakDays: streak.days,
});
}In practice
Introducing BFFs to unblock two teams
A retail platform had one API team serving a web app, an iOS app and an Android app. The API team had a nine-week backlog, both mobile teams were blocked on field additions, and the mobile apps made an average of eleven requests per screen.
Constraints
- One API team of four, nine-week backlog
- Two mobile teams of five, blocked on the API team
- Mobile screens averaging eleven requests, some on 3G networks
- A partner API with three integrators must remain stable
Decision
Give the web team and the mobile teams a BFF each, owned and deployed by them. Keep the existing API as the partner-facing contract with its versioning intact. The API team became a services team owning the domain services behind the BFFs.
Why
The nine-week backlog was a structural queue rather than a capacity problem: presentation concerns for three clients were all flowing through one team. Moving presentation aggregation to the teams that own the presentation removed the queue for the majority of requests, and left the API team owning the thing only they could own — the domain services.
What it cost
Three backends now exist where one did, and roughly 30% of the aggregation code is similar across them. The team accepted that deliberately: the duplicated code has three independent reasons to change, which is exactly the case where the DRY module said duplication is cheaper than a shared abstraction. They also added an explicit rule — no business decision in a BFF — and a quarterly review comparing the three, and they were clear that this arrangement needs three teams to sustain it and would be wrong at half the size.
A mobile team asks for a new endpoint that returns "everything for the home screen"
As a developer
Adds the endpoint to the shared API, since that is where endpoints live, and it is a reasonable request that will reduce mobile round trips.
As an architect
Notices that the shared API is accumulating screen-shaped endpoints for one client, which is a shared component acquiring per-client presentation concerns. That is the pressure the BFF pattern exists to relieve — but it is only worth relieving if the mobile team can own and operate their own backend. If they cannot, screen-shaped endpoints in the shared API are the honest lesser evil, and the decision should be recorded as such rather than drifting.
Your organisation has one web client and one small internal admin tool. A developer proposes a BFF per client. Is this justified?RevealHide
Almost certainly not, and the tell is that the pressure BFFs relieve is not present. That pressure comes from clients with genuinely conflicting needs — a mobile app fighting round trips, a partner needing stability, a web app iterating weekly — and from separate teams queueing behind a shared API. Two clients with similar needs and probably the same team have neither problem, so two BFFs would produce two deployables, two pipelines and duplicated aggregation to solve nothing. What is worth taking from the pattern even here is the principle: keep presentation shaping separate from domain logic, which can be a directory rather than a deployable. Revisit if a third client with different constraints arrives, or if a second team starts queueing.
Key takeaways
- A single API serving several clients averages across conflicting requirements and satisfies none of them well.
- A BFF is one backend per client experience, owned by the team that builds that experience.
- A gateway is shared and handles cross-cutting concerns; a BFF is per-client and handles aggregation. Use both, in that order.
- BFFs may aggregate and reshape; they must not make business decisions, or clients will diverge in behaviour.
- The pattern is justified by conflicting client needs and by teams queueing behind a shared API — not by client count.