Software Development
Backend for frontend: a practical guide for architects
7 August 2026

A Backend for Frontend (BFF) is a thin, per-client server-side layer that aggregates downstream calls, reshapes responses for a specific UI, and enforces perimeter concerns such as authentication, rate limiting, and header sanitisation. The decision rule is straightforward: adopt a BFF when clients have divergent data shapes, independent release cadences, token isolation requirements, or when the aggregation complexity per user action is high enough to warrant server-side fan-out. Sam Newman’s foundational write-up establishes that the BFF is part of the application, not a shared infrastructure component, and Phil Calçado’s original practitioner account reinforces that ownership and deployment must be shared with the corresponding UI team. The Microsoft Azure Architecture Center documents the pattern in production-grade deployments, and SoundCloud’s engineering team pioneered it during their monolith decomposition. If your system exhibits any of the four signals above, the concrete next step is a two-week discovery spike that measures aggregation complexity, team ownership boundaries, and the latency budget for the critical screen.
Table of Contents
- What problems does a general-purpose API create for frontends?
- What a backend for frontend actually does
- When is a BFF justified?
- How should you design a BFF architecture?
- What do real BFF request flows look like?
- How to implement a BFF step by step
- How do you operate BFFs reliably at scale?
- How do you introduce BFFs into an existing system?
- How Vicedomini Softworks designs and delivers BFF architectures
- Key takeaways
- The case for starting smaller than you think
- Vicedomini Softworks: architecture review and BFF pilot
- Useful sources
- FAQ
What problems does a general-purpose API create for frontends?
The symptoms of a misaligned API surface are recognisable long before teams articulate the root cause. Common indicators include:
- Frontend clients making five or more downstream calls to assemble a single screen.
- Payload mismatch: mobile clients receiving desktop-sized JSON responses and discarding most fields.
- Frontend teams blocked on API changes because a central backend team owns the contract.
- Access tokens or refresh tokens exposed in browser memory or localStorage, creating unnecessary attack surface.
- Divergent versioning: a mobile app on v2 and a web SPA on v4 of the same endpoint, with the backend team maintaining both.
- Latency spikes caused by the client serialising sequential calls that could be parallelised server-side.
A concrete illustration: a mobile client on a constrained 4G connection needs a compact summary card for a user’s recent orders, pulling from an orders service, a product catalogue, and a promotions engine. A desktop web client rendering the same screen needs richer data, including full product images, related recommendations, and account-level pricing. A single general-purpose endpoint either over-fetches for mobile or under-fetches for desktop. The mobile team works around it with client-side filtering; the desktop team adds supplementary calls. Both workarounds accumulate as technical debt.
The organisational root cause is well-described by Conway’s Law: when a single backend team owns the API, the API reflects that team’s structure and release cadence rather than the needs of the consuming UIs. Frontend teams lose autonomy, and every API change requires cross-team negotiation. SoundCloud encountered precisely this friction during their transition from a monolith to microservices, and the BFF pattern emerged as a structural response to it.
What a backend for frontend actually does
A BFF is not a proxy and not a domain service. The HLD Handbook’s practitioner definition is precise: it is a thin service that aggregates downstream calls, reshapes responses into a presentation model, and enforces perimeter concerns. Those three responsibilities are worth unpacking individually.
Aggregation (fan-out): The BFF issues parallel requests to multiple downstream microservices and assembles the results into a single response. The client makes one call; the BFF makes many. This moves network complexity from the client to a server-side layer where timeouts, retries, and partial failures can be handled gracefully.

Response shaping: The BFF transforms the aggregated data into a model that matches the UI’s exact needs. Fields are renamed, nested structures are flattened, units are converted, and irrelevant data is stripped. The result is a payload the frontend can render without further transformation.
Perimeter enforcement: Authentication token exchange, rate limiting, CORS policy, and header sanitisation all belong at the BFF boundary. A single-page application should not hold long-lived access tokens; the BFF, acting as a confidential OAuth client under RFC 6749, performs the token exchange server-side and issues short-lived session cookies with HttpOnly and SameSite=Strict attributes.
What does not belong in a BFF is business logic. Pricing rules, eligibility calculations, and domain validation must remain in domain services. The moment a BFF starts encoding business decisions, it becomes a domain service in disguise, and the ownership model breaks.
A BFF should be so thin that replacing it is a two-day task. If replacing it would require a domain expert, it has accumulated the wrong responsibilities.
Pro Tip: Assign BFF ownership to the frontend team, not the platform team. The team that ships the UI must own the BFF, share its release cadence, and participate in its on-call rotation. This single rule prevents more architectural drift than any governance framework.
When is a BFF justified?

The decision is not binary, but the signals are clear enough to structure as a checklist.
Signals that favour adopting a BFF:
- Three or more distinct client types (mobile native, desktop web, partner API, voice/IoT) with materially different data shape requirements.
- A single user action requires aggregating data from two or more downstream services, and the client cannot tolerate the latency of sequential calls.
- Frontend teams operate on independent release cadences and are blocked by a shared backend team’s sprint cycle.
- Token isolation is a regulatory or security requirement: tokens must not be held in browser storage, or a confidential OAuth client is mandated by policy.
- A third-party partner integration requires a tailored API surface that must not expose internal service topology.
Signals that argue against:
- Only one client type exists and no second client is planned within a credible roadmap horizon.
- The application is predominantly CRUD with minimal aggregation: clients call one service and render the response directly.
- All clients make identical requests and receive identical responses; there is no divergence to justify per-client ownership.
- The extra network hop would push the latency budget beyond acceptable limits and the aggregation benefit does not compensate.
Decision flow:
- Count distinct client types. If fewer than two, stop here; a BFF adds overhead without benefit, as the HLD Handbook confirms.
- Measure aggregation depth. Count the number of downstream service calls required to render the most complex screen for each client. If the number exceeds two for any client, proceed.
- Assess team ownership. Determine whether the frontend team can own and deploy a server-side component. If not, resolve the organisational constraint first.
- Evaluate the latency budget. Measure the round-trip cost of the extra hop. If the aggregation saving exceeds the hop cost, the BFF is justified.
- Check regulatory constraints. If token isolation or data residency rules apply, a BFF is often mandatory regardless of aggregation depth.
How should you design a BFF architecture?
How many BFFs to create
The guiding principle is one experience, one BFF. A mobile native app gets its own BFF; a desktop web SPA gets its own; a third-party partner API gets its own. This boundary preserves independent release cadences and prevents one client’s requirements from polluting another’s contract.
Sharing a BFF across similar clients is acceptable when the clients are genuinely similar: two mobile platforms (iOS and Android) consuming an identical data shape may share a single BFF, provided the team accepts that any change affects both. The rule-of-three applies to shared logic extraction: if the same aggregation logic appears in three or more BFFs, extract it into a shared internal service. Until that threshold is reached, duplication is preferable to tight coupling, a lesson SoundCloud learned operationally.
REST vs GraphQL inside a BFF
GraphQL can be implemented inside a BFF to give the client flexible, field-level query control without exposing the full graph to the public internet. This is a sound pattern when the client’s data requirements are genuinely variable and the team has GraphQL expertise. However, GraphQL does not automatically remove the need for a per-client BFF in a multi-client product. As the Azure Architecture Center notes, GraphQL federation is a separate concern from per-client ownership; a federated graph and a BFF can coexist, with the BFF acting as the composition layer that issues federated queries on behalf of its client.
REST remains the simpler choice when the client’s data requirements are stable and well-understood. The BFF exposes a small set of UI-shaped REST endpoints and handles aggregation internally.
Caching strategy
Cache at the BFF boundary for responses that are expensive to aggregate and have a predictable TTL. Short-lived caches (10–60 seconds) are appropriate for user-specific aggregated responses; longer TTLs suit reference data such as product catalogues or configuration. Cache invalidation should be event-driven where possible: a downstream service publishes a change event, and the BFF invalidates the relevant cache key. Avoid caching at the API gateway layer for user-specific responses, as gateway caches are typically keyed on URL and headers and do not account for user context.
Security and perimeter placement
The BFF is the confidential OAuth client. It holds client credentials, performs the authorisation code exchange, and stores tokens server-side. The browser receives only a session cookie. This pattern, grounded in RFC 6749, removes long-lived tokens from browser storage entirely. Header sanitisation at the BFF boundary prevents internal service headers (correlation IDs, internal routing hints) from leaking to the client. The AWS blog on the BFF pattern recommends treating the BFF as part of the application perimeter, not as a transparent proxy.
Pro Tip: Never forward raw Authorization headers from the client to downstream services. The BFF should exchange the inbound session for a short-lived internal token scoped to the specific downstream service, limiting blast radius if a downstream service is compromised.
Gateway vs BFF vs federation: responsibilities at a glance
| Layer | Primary responsibility | Owns business logic? | Per-client? |
|---|---|---|---|
| API gateway | Traffic routing, TLS termination, global rate limiting | No | No |
| BFF | Aggregation, response shaping, perimeter auth | No | Yes |
| Federation / composition layer | Cross-service graph stitching, schema ownership | No | No |
| Domain microservice | Business logic, data persistence | Yes | No |
What do real BFF request flows look like?
Mobile-first flow (bandwidth-conscious)
A mobile client sends a single authenticated request to the API gateway. The gateway enforces TLS, validates the session cookie, and routes the request to the mobile BFF. The BFF fans out in parallel to three downstream microservices: a user profile service, an activity feed service, and a notifications service. It assembles a compact response, stripping fields the mobile UI does not render, and returns a single JSON payload. The identity provider is involved only at session establishment; the BFF holds the access token server-side and attaches it to downstream calls internally.
Cached mobile flow (API gateway cache short-circuit)
For reference data (product lists, configuration), the API gateway holds a short-lived cache keyed on the request path and a client-type header. A cache hit returns the response without reaching the BFF, reducing both latency and downstream load. A cache miss proceeds to the BFF, which aggregates, caches the result internally with a matching TTL, and returns the response. The gateway and BFF TTLs must be aligned to prevent stale data at the gateway outlasting a fresher BFF cache.
Desktop/SSR flow (data-rich single response)
A server-side rendered desktop application issues a request from the rendering server, not the browser. The desktop BFF receives the request, fans out to a broader set of downstream services (including analytics, recommendations, and account management), and returns a richer payload. Because the rendering server is close to the BFF on the network, the extra hop cost is negligible. The browser receives fully rendered HTML; no client-side API calls are required for the initial page load.
The most underestimated BFF design decision is not the aggregation logic but the placement of the BFF relative to the data. Edge placement reduces client-to-compute latency; server-near-data placement reduces compute-to-data latency. For heavy aggregation, the latter almost always wins.
| Flow | Aggregation depth | Recommended placement | Cache layer |
|---|---|---|---|
| Mobile first | High (3+ services) | Server-near-data | BFF in-memory + gateway TTL |
| Cached mobile | Low (reference data) | Edge or gateway | Gateway cache primary |
| Desktop/SSR | Very high (5+ services) | Server-near-data | BFF in-memory |
How to implement a BFF step by step
Preflight tasks
Before writing a line of BFF code, three measurements are necessary. First, instrument the existing client to count downstream calls per screen and record payload sizes. Second, map ownership: identify which team currently owns each downstream service and confirm the frontend team has the organisational mandate to own a server-side component. Third, evaluate the runtime: determine whether the BFF will run as a containerised service on Kubernetes, as a serverless function, or within a server-side framework such as Next.js or Remix, which can collapse BFF responsibilities into the frontend project for single-origin applications.
Implementation checklist
- Pair the frontend team with a backend engineer for the initial spike; the BFF must be owned by the frontend team from day one.
- Define the API contract using an OpenAPI specification or GraphQL schema before writing implementation code. Contract-first development prevents scope creep.
- Implement the fan-out aggregation for one screen only. Resist the temptation to generalise.
- Add timeouts on every downstream call. A downstream service that hangs must not hang the BFF response.
- Implement retries with exponential backoff and jitter for idempotent calls. Non-idempotent calls (POST, PATCH) must not be retried automatically.
- Add circuit breakers using a library such as Resilience4j (JVM) or the equivalent for your runtime. A tripped circuit must return a graceful degraded response, not a 500.
- Write consumer-driven contract tests against each downstream service. Tools such as Pact enforce that downstream changes do not silently break the BFF.
- Deploy behind the API gateway with health check endpoints and structured logging from the first deployment.
- Set SLOs for the BFF endpoint before releasing to production. Define P95 latency targets and error rate thresholds.
- Align the BFF release pipeline with the frontend’s CI/CD pipeline so that a single pull request can ship both UI and BFF changes atomically.
Vercel’s seven-step implementation guide reinforces the importance of runtime placement decisions and warns explicitly against scope creep during the initial implementation phase.
Pro Tip: Use mock servers (WireMock, Mockoon) during BFF development so the frontend team can iterate on the API contract without depending on live downstream services. This decouples frontend and downstream release cycles during the build phase.
API design guidance
BFF endpoints should be UI-shaped, not resource-shaped. An endpoint named /home-feed that returns everything the home screen needs is preferable to three separate resource endpoints the client must call and join. Versioning strategy for BFF APIs should favour URL versioning (/v2/home-feed) over header versioning, as URL versioning is easier to monitor, cache, and route at the gateway layer. Deprecate old versions with a sunset header and a minimum 90-day notice period to allow frontend teams on older versions to migrate.
How do you operate BFFs reliably at scale?
Deployment patterns
Three deployment topologies are common. A containerised BFF colocated with the frontend application server minimises the hop cost for SSR applications and simplifies deployment pipelines. An edge-deployed BFF (serverless functions at CDN edge nodes) reduces client-to-compute latency for geographically distributed users but increases compute-to-data latency for heavy aggregation workloads. A centralised BFF cluster near the data tier is the right choice when aggregation depth is high and downstream services are colocated in the same data centre or cloud region. The Vercel implementation guide notes that runtime placement mistakes are among the most common BFF operational errors: edge deployment is attractive but often wrong for aggregation-heavy BFFs.
Observability signals
Track the following metrics for every BFF in production:
- Request latency at P50, P95, and P99 for each endpoint.
- Downstream fan-out count per request (how many service calls the BFF issued).
- Downstream error rate and timeout rate, broken down by service.
- Cache hit ratio for cached endpoints.
- Authentication failure rate and rate-limit event count.
- Error budget consumption against the defined SLO.
Structured logs should include a correlation ID that propagates through all downstream calls, enabling distributed tracing across the full fan-out graph. OpenTelemetry is the standard instrumentation framework for this purpose.
SLOs and error budgets
Set SLOs at the BFF level, not only at the downstream service level. An aggregated endpoint that calls three services inherits the failure probability of all three; its SLO must account for this. A practical starting point is to set the BFF P95 latency target at 1.5 times the slowest downstream P95, and the error rate SLO at the product of the downstream error rates plus a margin for BFF-specific failures.
Pro Tip: Share the BFF on-call rotation with the frontend team, not the platform team. When the team that owns the UI is paged for BFF incidents, they have the full context to diagnose whether the failure is in the aggregation logic, the downstream service, or the client contract.
How do you introduce BFFs into an existing system?
Incremental migration is the only low-risk path. A full-system BFF adoption attempted in a single sprint invariably stalls on ownership disputes and integration complexity.
The recommended approach begins with a pilot: select one high-complexity screen, measure its current aggregation depth and payload size, and introduce a strangler endpoint in a new BFF service that handles only that screen. The strangler pattern allows the old API path to remain active while the new BFF path is validated in production with a small percentage of traffic.
Pilot success metrics should be defined before the pilot begins. Useful measures include: reduction in client-side API calls per screen render, reduction in payload size delivered to the client, and reduction in frontend developer cycle time for changes to that screen’s data contract. These metrics provide the evidence base for expanding the BFF to additional screens.
Risk controls during rollout include feature flags to switch individual clients between the old API path and the new BFF path, observability dashboards tracking error rates and latency for both paths simultaneously, and a documented fallback procedure that reverts to the old path within minutes if the BFF path degrades. Phased cutover, moving 5%, then 25%, then 100% of traffic to the BFF path, limits blast radius.
Pro Tip: When measuring the true cost of the extra network hop, distinguish between compute-to-data latency and edge-to-client latency. A BFF placed near the data tier adds negligible hop cost for server-side rendering workloads, because the hop is a sub-millisecond internal network call. The hop cost that matters is the one between the client and the BFF, which is why edge placement is attractive for mobile clients but often counterproductive for aggregation-heavy workloads.
How Vicedomini Softworks designs and delivers BFF architectures
Vicedomini Softworks has applied the BFF pattern across multi-client product engagements where regulatory token isolation, divergent mobile and web data shapes, and independent frontend release cadences were all present simultaneously. A representative architecture involves an API gateway handling TLS termination and global rate limiting, two per-experience BFFs (one for the mobile native client, one for the web SPA), a shared internal service for reference data that crossed the rule-of-three threshold, and an observability stack built on OpenTelemetry with distributed tracing across the full fan-out graph.
The mobile BFF was implemented in Spring Boot on Red Hat OpenShift, colocated with the downstream microservices to minimise compute-to-data latency. The web BFF was implemented in Next.js, collapsing the BFF responsibilities into the frontend project for the SSR rendering path. Both BFFs acted as confidential OAuth clients, performing token exchange server-side and issuing HttpOnly session cookies to their respective clients.
The most consistent lesson from multi-client BFF delivery is that ownership disputes cause more production incidents than technical complexity. When the frontend team owns the BFF from day one, the number of cross-team escalations drops sharply.
Observed outcomes included a material reduction in client-side API calls per screen, faster feature delivery for the mobile team (who could evolve their BFF contract without waiting for a central backend release), and a cleaner security boundary that satisfied the client’s regulatory requirements for token handling.
Discovery and procurement checklist for BFF adoption:
- Confirm the frontend team has the mandate and capability to own a server-side component.
- Measure aggregation depth for the three most complex screens.
- Identify token isolation requirements and map them to the OAuth client model.
- Define the runtime placement strategy (colocated, edge, or server-near-data) before writing code.
- Agree on the rule-of-three extraction policy before the first BFF is deployed.
- Set SLOs and observability requirements as acceptance criteria for the pilot.
Pro Tip: Request a two-week architecture spike as the first engagement deliverable. A spike that measures aggregation complexity, maps ownership boundaries, and produces a runtime placement recommendation costs a fraction of a full implementation and eliminates the most common reasons BFF adoptions stall.
Vicedomini Softworks’s engineering and consulting services cover the full BFF delivery lifecycle, from architecture review and pilot through to production deployment and ongoing support.
Key takeaways
The single most important determinant of BFF success is ownership: the team that ships the client must own the BFF, share its release cadence, and participate in its on-call rotation.
| Point | Details |
|---|---|
| Ownership is the critical variable | The frontend team must own the BFF; misaligned ownership reintroduces the cross-team bottlenecks the pattern is designed to remove. |
| Keep BFFs thin | Aggregate, reshape, and enforce the perimeter; never encode business logic in a BFF or it becomes a domain service in disguise. |
| Apply the rule of three | Extract shared logic from BFFs only after it appears in three or more; until then, duplication is preferable to tight coupling. |
| Placement determines latency | Edge deployment reduces client-to-compute latency; server-near-data placement reduces compute-to-data latency; heavy aggregation almost always favours the latter. |
| Vicedomini Softworks delivers BFF architectures | Vicedomini Softworks designs and implements per-client BFF solutions for multi-client products across EMEA and North America, covering architecture review, pilot, and production support. |
The case for starting smaller than you think
Most teams that struggle with BFF adoption do so because they scope the first BFF too broadly. The instinct is to design a complete BFF for every client type before writing a line of code, producing an architecture document that satisfies every stakeholder but delays the moment of real measurement. The teams that succeed start with a single screen, a single BFF, and a clear set of pilot metrics. They learn from the aggregation complexity, the ownership friction, and the latency profile of that one screen before generalising.
The governance question is equally important and equally underestimated. Without a named owner for each BFF, a rule-of-three extraction policy, and a documented anti-pattern list, BFF architectures drift towards the shared-fat-BFF failure mode within six months of initial deployment. The pattern is not self-governing; it requires deliberate organisational decisions that must be made before the first BFF goes to production.
The concrete recommendation: run a two-week aggregation and latency spike for the most complex screen in the product. Measure the current call count, payload size, and developer cycle time. Use those numbers to make the adoption decision, not architectural intuition.
Vicedomini Softworks: architecture review and BFF pilot
Vicedomini Softworks works directly with engineering teams and technical decision-makers to design, pilot, and deliver BFF architectures for multi-client products. The engagement model removes the account-manager layer, placing architects and senior engineers in direct contact with the client team from the first discovery session.

For organisations evaluating BFF adoption, the starting point is an architecture review that measures aggregation complexity, maps ownership boundaries, and produces a runtime placement recommendation. For teams ready to move faster, a structured pilot delivers a production-grade BFF for one client experience within a defined timeframe, with SLOs, observability, and a documented migration path for the remaining clients. Vicedomini Softworks’s technology stack, including Spring Boot, Quarkus, Next.js, GraphQL, and Red Hat OpenShift, covers the full range of runtime environments where BFFs are deployed in enterprise and SaaS products. To discuss an architecture review or request a pilot assessment, visit Vicedomini Softworks’s services page.
Useful sources
The following references provide authoritative depth on the BFF pattern and its related concerns.
- Backends For Frontends - Sam Newman
- Backends For Frontends - Azure Architecture Center
- Backend for Frontend: Per-Client API Aggregation Done Right - The HLD Handbook
- Service Architecture at SoundCloud — Part 1
- How to implement the backend for frontend pattern in 7 steps - Vercel
- Backends for Frontends pattern - AWS blog
- The Back-end for Frontend Pattern (Phil Calçado)
- The OAuth 2.0 Authorization Framework (RFC 6749)
FAQ
What is a backend for frontend?
A backend for frontend is a thin, per-client server-side layer that aggregates downstream service calls, reshapes responses for a specific UI, and enforces perimeter concerns such as authentication and rate limiting. Each client type (mobile, desktop, partner) has its own dedicated BFF.
How does a BFF differ from an API gateway?
An API gateway handles traffic routing, TLS termination, and global rate limiting across all clients; it is not per-client. A BFF is per-client, owns the aggregation and response shaping logic for one UI, and acts as a confidential OAuth client. The two components are complementary, not interchangeable.
Is Python a backend or frontend language?
Python is a backend language. It runs server-side and is commonly used for API development, data processing, and scripting; it does not execute in the browser. A BFF can be implemented in Python, though JVM frameworks (Spring Boot, Quarkus) and Node.js runtimes are more common in enterprise BFF deployments.
How do you add a backend to a frontend application?
The standard approach is to introduce a BFF as a server-side service that the frontend calls instead of downstream microservices directly. For single-origin applications, server-side frameworks such as Next.js or Remix can collapse BFF responsibilities into the frontend project. For multi-client products, an explicit per-client BFF service is required.
When should you avoid using a BFF?
Avoid a BFF when only one client type exists, when the application is predominantly CRUD with minimal aggregation, or when all clients make identical requests. In these cases, the extra network hop increases latency and operational overhead without a compensating benefit, as the HLD Handbook confirms.
Recommended
- L’Architettura Multi-Agente di Stroncami.it e la Transizione da UX ad AX — Vicedomini Softworks
- Progettazione dei dati nell’ingegneria del software: una guida completa — Vicedomini Softworks
- I migliori — Vicedomini Softworks
- Astro: il framework moderno che sta ridefinendo l’editoria web — Vicedomini Softworks