Acumatica · Bff

BFF Pattern — Backend for Frontend

BFF Pattern — Backend for Frontend is the work that makes the systems talk. The API is the contract between the producer and the consumer; the contract is what determines whether.

John Kihiu12 min read

Backend for Frontend (BFF) is a simple idea that solves a real problem: a single general-purpose API rarely serves a web client, a mobile client, and a third-party integration equally well. Instead of forcing every consumer through one generic gateway, you build a thin backend per frontend — each shaped around what that specific client actually needs. The pattern earns its keep the moment a mobile team starts asking for a "lite" version of an endpoint that a web team also depends on.

The problem BFF solves

A shared API tends to accumulate optional fields, conditional includes, and query parameters that toggle behaviour for one client without breaking another. Over time, the endpoint becomes a compromise nobody is happy with: too heavy for mobile, too narrow for the admin dashboard, too generic for a partner integration. A BFF sidesteps this by giving each frontend its own backend layer that composes calls to downstream services — often the same services the shared API would have called — and shapes the response exactly to what that UI renders.

Where it sits in the architecture

The BFF sits between the client and your domain services or microservices. It is not a replacement for those services — it is an aggregation and translation layer. A typical request from a mobile app hits the mobile BFF, which fans out to an orders service, a pricing service, and a user-profile service, then assembles one response tuned for the mobile screen. The web BFF might call the same three services but return a richer payload because the web client renders more on one page. Neither BFF owns business logic; that stays in the domain services. The BFF owns orchestration, response shaping, and client-specific concerns like session handling or field trimming.

One BFF per experience, not per client type

The rule of thumb is one BFF per distinct user experience, not one per device. If your iOS and Android apps render the same screens with the same data needs, they can share a mobile BFF. Splitting further than the UI actually diverges just multiplies the surface area you have to maintain.

A minimal BFF endpoint

The implementation is usually unremarkable — a thin HTTP layer that calls a few downstream services in parallel and merges the results. Here is the shape of a mobile order-summary BFF endpoint written against a couple of internal services:

TYPESCRIPT · BFF ENDPOINT
// mobile-bff/routes/orderSummary.ts
app.get('/mobile/orders/:id/summary', async (req, res) => {
  const { id } = req.params;

  const [order, tracking, customer] = await Promise.all([
    ordersService.getOrder(id),
    shippingService.getTracking(id),
    customersService.getProfile(req.auth.customerId),
  ]);

  // Mobile only needs a slim projection - no line-item tax
  // breakdowns, no internal SKUs, no admin metadata.
  res.json({
    orderId: order.id,
    status: order.status,
    total: order.total,
    eta: tracking?.estimatedDelivery ?? null,
    customerName: customer.firstName,
  });
});

Trade-offs and when to skip it

BFFs add an extra hop and an extra service to deploy, monitor, and keep alive. For a product with one client and one team, a BFF is pure overhead — you would be building an aggregation layer with nothing to aggregate against. The pattern pays off once you have genuinely divergent clients maintained by different teams on different release cadences, because it lets each team version and ship their BFF independently of the others. It also becomes attractive when the alternative is a shared API team turning every client request into a negotiation over a shared contract.

Watch for logic creep

The most common failure mode is business logic quietly migrating into the BFF because it is convenient — a discount calculation here, a status derivation there. Once two BFFs implement the same rule slightly differently, you have a consistency bug that is hard to trace. Keep domain logic in the domain services; the BFF composes and shapes, it does not decide.

BFF vs. API gateway

These two are often confused. An API gateway is a single, shared entry point that handles cross-cutting concerns — auth, rate limiting, routing — for all clients uniformly. A BFF is deliberately client-specific and can contain aggregation logic tailored to one experience. In practice they coexist: the gateway sits in front of everything for auth and routing, and individual BFFs sit behind it, each serving one type of client. Teams sometimes start with a gateway, notice it accumulating client-specific branches, and split those branches out into proper BFFs once the divergence becomes unmanageable.

Wrapping up

BFF is not a framework or a product — it is an organisational pattern for when one API can no longer serve every client without compromise. Build one per distinct frontend experience, keep business logic in the services it calls, and resist the urge to reach for it before you actually have more than one client pulling the shared API in different directions.

John Kihiu
Acumatica ERP Developer · Laravel Engineer

Independent software engineer in Nairobi specialising in Acumatica customisations, Laravel backends, and tax fiscalisation integrations across East and Southern Africa.