Backends for Frontends: The API You Actually Need
When the backend API is not built for your UI — and how a BFF layer gives you the API you need without waiting for another team.
Here's a situation I've hit more than once: the backend team has great engineers following best practices for distributed microservices. The API they've built is well-designed — for a backend. For a frontend, it's painful.
The specific version I remember: 12 separate API calls to assemble the complete user model. Who is the user, what are their permissions, what billing plan are they on, what organizations do they belong to, are they currently suspended. Fanning out 12 network requests from the browser to render a profile page. Not because anyone was being malicious — because that's how the microservices were designed to communicate with each other, and the frontend was just another consumer.
The Backend for Frontend (BFF) pattern addresses exactly this.
What a BFF Is
A BFF is an API layer owned by the frontend team that sits between the UI and the backend services. It speaks in terms of what the UI needs, not what the backend exposes.
Instead of the browser making 12 requests and assembling the user model from the pieces, the browser makes one request to the BFF. The BFF fans out to the 12 services, assembles the model, and returns exactly what the UI needs for that view.
Before:
Browser → Service A → (wait)
Browser → Service B → (wait) × 12
Browser → Service C → (wait)
After:
Browser → BFF → Service A, B, C (parallel)
← assembled responseThe latency win comes from running the fan-out server-side (or at the edge) where network hops between services are fast and cacheable, rather than from the user's browser over a variable internet connection.
Why the Edge Makes Sense for This
Running a BFF at the CDN edge — Lambda@Edge, Vercel Edge Functions, Cloudflare Workers — puts the aggregation as close to the user as possible. The BFF fetches from backend services (which are usually in a data center), but the user's request hits a node geographically near them. Round trips between the BFF and backend services happen on fast, internal infrastructure rather than over the public internet.
Next.js server components and SvelteKit's load functions are doing this pattern natively — data fetching co-located with the component, running server-side, composing the response the UI needs. If you're using either of these frameworks, you're already doing a form of BFF without calling it that.
The Practical Objections
Politics. Backend teams have opinions about frontend teams managing server infrastructure. Security teams have opinions about where requests originate and who controls the service. Frontend on-call is typically much lighter than backend on-call — and if you own a BFF, you're now on the hook for a service that can go down.
These are real concerns, not just friction to dismiss. I've been in architecture discussions where the right answer was technically clear and organizationally unfeasible. The BFF adds something to the reliability surface area that the frontend team has to own and monitor.
Complexity. The BFF is another node that can fail. Another thing to deploy. Another service to monitor. The same principle applies here as everywhere else: add complexity only when the cost it removes is greater than the cost it introduces.
Scope. You probably don't need a BFF for every API. The case for it is specific: when the backend API shape is genuinely incompatible with what the UI needs, and changing the backend is not an option. Not as a general principle, but as a targeted tool for a specific pain.
When It's Clearly Worth It
The clearest case: you've inherited an API you can't change, it's expensive for the UI to use (too many round trips, wrong data shape, too coarse or too granular), and you need to ship. A thin BFF layer lets you own the translation layer rather than embedding it as complex client-side code that nobody wants to maintain.
The second case: you're doing significant data transformation between what the backend provides and what your design requires. Doing that transformation server-side (in the BFF) is faster and more reliable than doing it in the browser.
The non-case: you have control over the backend, or the backend already returns what you need. Adding a BFF layer because it sounds architecturally clean is adding complexity for no benefit.
Like everything else in this course: the pattern is a tool. The tool is worth using when the problem it solves is one you actually have.
Keep reading
Enjoyed this? Get more like it.
Deep dives on system design, React, web development, and personal finance — straight to your inbox. Free, always.