A backend-for-frontend (BFF) is a dedicated API layer built for one specific client — web, iOS, Android, a partner integration — instead of one generic API serving every client's needs at once. Teams add a BFF when a single shared API has to keep compromising: adding fields only mobile needs, aggregating calls only the web dashboard wants, versioning around one client's release cycle while breaking another's. A BFF fixes this by giving each client its own backend, owned by the team that owns that client, shaped exactly for what that client needs and nothing else.
The core idea
A generic API trying to serve a mobile app, a web dashboard, and a partner integration equally well tends to serve all three poorly. Mobile wants minimal payloads and fewer round trips because of battery and network cost. A web dashboard wants rich, aggregated data assembled from several backend services in one call. A partner integration wants a stable, versioned contract that will not change on the web team's release schedule. One shared API optimizing for all three ends up as a set of compromises nobody is fully happy with, plus a growing pile of client-specific conditional logic inside a supposedly generic layer.
A BFF resolves this by moving that client-specific shaping out of the shared backend entirely. The shared services stay generic and focused on their own domain; each BFF calls into them, aggregates and reshapes the results, and returns exactly what its one client needs. The team that owns the mobile app can also own the mobile BFF, deploying changes on its own schedule without touching a shared API other clients depend on.
Implementation options
| Approach |
How it works |
Fits best when |
| REST BFF per client |
A small Node/Go/Python service per client type, calling downstream services and reshaping responses |
Client needs diverge significantly and teams want independent deploys |
| GraphQL BFF |
One GraphQL layer per client (or a federated schema), letting each client query exactly the fields it needs |
Client needs vary in shape more than in aggregation logic; see how to learn GraphQL |
| BFF as part of the gateway |
Client-specific routes and transformations live inside the API gateway layer itself |
Small number of clients, team wants to avoid standing up separate services |
| Shared generic API, no BFF |
One API serves all clients with optional fields and versioning |
Client needs are similar enough that divergence has not become a real problem yet |
Common mistakes
- Building one BFF shared by all clients "to keep things simple." A BFF used by every client is just the generic API you were trying to move away from, with an extra hop added. The pattern only earns its cost when each client genuinely gets its own layer.
- Duplicating business logic inside the BFF. A BFF should aggregate and reshape data, not reimplement domain rules that belong in the underlying services. Logic duplicated across BFFs and services drifts out of sync over time.
- Letting the BFF grow into its own monolith. Without discipline, a BFF accumulates unrelated features until it is a second backend to maintain. Keep it scoped to presentation-shaping and aggregation for its one client.
- No clear ownership boundary with backend teams. A BFF works best when the client team owns it end to end. If backend teams end up maintaining BFFs for clients they do not build, the ownership benefit that justified the pattern disappears.
FAQ
Is a BFF the same as an API gateway?
No. A gateway is a shared entry point handling cross-cutting concerns like auth and rate limiting for all clients uniformly. A BFF is client-specific, shaping data for exactly one client's needs. They are often used together — see API gateway vs service mesh for how the gateway layer fits alongside client-specific services.
Do I need a BFF for every client type?
Only the ones whose needs genuinely diverge from a shared API. A partner integration with simple, stable needs might be fine against the generic API while mobile and web each get their own BFF.
Who should own a BFF?
Ideally the same team that owns the client it serves. That is the core benefit of the pattern — the mobile team can change the mobile BFF without coordinating a shared API change with every other client team.
Does GraphQL replace the need for a BFF?
Not entirely. A federated GraphQL schema can reduce the need for separate REST BFFs, but teams still often run a thin GraphQL layer per client to control exactly which parts of the federated schema that client can query.
Where to go next
For where the BFF's client-facing responsibilities end and the shared entry point's begin, see API gateway vs service mesh. If you are building a GraphQL-based BFF, how to learn GraphQL covers the schema fundamentals, and how to build a REST API in Node is the equivalent starting point for a REST-based one.