BFF Pattern: When to Use It, How to Structure It

A Backend for Frontend (BFF) is a thin server-side API tailored to a specific client — the web app, the iOS app, the third-party embed.

Backend for Frontend (BFF): When a Dedicated API Layer Per Client Actually Helps

The BFF pattern, popularized by Phil Calçado at SoundCloud, addresses a common tension: a single general-purpose API tries to serve web, mobile, and partner clients and ends up serving none of them well. Web wants deeply nested payloads to render a full page in one round-trip; mobile wants minimal payloads to conserve bandwidth and battery; partners want a stable versioned surface with slower change cadence. A BFF splits that responsibility — each client gets its own API layer, owned ideally by the same team that owns the client. Underneath, both BFFs call the same domain services.

When BFF is the right shape

Strong signals: multiple client types with materially different data needs; frontend teams frustrated by API shapes that don't match their view models; N+1 problems where the client fans out to many backend services per screen; a desire to move client-specific logic (formatting, aggregation, feature flagging) out of the client without polluting domain services. Weak signals: only one client (web) exists; the team is small enough that one API team can serve everyone. Anti-signals: teams that will use BFFs as a place to smuggle business logic that belongs in domain services.

Ownership: the team that owns the client owns the BFF

This is the load-bearing rule. If the platform team owns the BFF, it becomes a bottleneck and drifts toward being a generic API again. When the web team owns the web BFF, changes to it are one PR, one code review, one deploy — no cross-team ticket. Practical implication: BFFs are usually written in the same language and framework as the client (Node.js for web BFFs, sometimes Kotlin for Android, Swift server frameworks are rare but possible). The team's existing skills transfer directly.

Boundaries — what belongs in the BFF vs. downstream

Belongs in BFF: client-specific data shaping (rename fields, flatten nested objects, format dates), aggregation across multiple domain calls into a single client response, client-specific caching (page-level cache with client's cache keys), authorization checks specific to what this client shows (hide fields based on plan tier the client renders differently). Does NOT belong: business rules (pricing, entitlement, workflow state transitions), persistent data, anything a second client would need to reimplement. If you find yourself copying logic between two BFFs, it belongs in a shared service, not in each BFF.

GraphQL as an alternative or complement

GraphQL was in part a response to the same problem BFFs address — letting the client specify what it needs. A single GraphQL gateway can reduce the need for per-client BFFs by letting each client query exactly what it wants. Trade-off: GraphQL centralizes ownership (someone owns the schema; changing it requires that team's approval) where BFFs decentralize it. Hybrid works: GraphQL gateway underneath, thin BFFs on top only for clients with substantial aggregation or protocol translation needs (e.g., a partner BFF exposing REST over the internal GraphQL).

Operational realities

Each BFF is another service to deploy, monitor, and secure. If you have 3 clients, that's 3 additional services with their own on-call, SLOs, and incident history. Set explicit SLOs per BFF (usually tighter than downstream services because they're user-facing). Instrument the fan-out: a single BFF call may hit 5-10 domain services, and knowing which downstream slowed a page load is essential. Use distributed tracing (OpenTelemetry) from day one. Failure isolation: a BFF failure should degrade one client, not cascade — never share databases, caches, or thread pools across BFFs.

Frequently asked questions

Isn't a BFF just a monolith with extra steps?
Only if you push business logic into it. A well-scoped BFF is orchestration and presentation — hundreds of lines, not thousands per endpoint. If a BFF grows to look like a full application, business logic has leaked in and needs to migrate down.
How do we handle authentication in a BFF?
Two common patterns: (1) BFF terminates auth (validates the token, maps to a user), passes an internal identity token downstream. (2) BFF passes the user's token through and lets each downstream service validate. Pattern 1 is cleaner and more common; pattern 2 is simpler when domain services already need to know the caller anyway.
Do we need a BFF if we're using Next.js with API routes?
Next.js API routes and server components are already a form of BFF — code that runs server-side, shapes data, and returns exactly what the page needs. If that pattern is working, don't add another layer for the sake of an architecture diagram.

Related fundraising guides (40)

Investor directory · Fundraising library · Articles A–Z · Company funding database