The Backends for Frontends (BFF) Pattern

Many textbooks assume that your frontend will just call a single, beautiful, and secure API, but in the real-world this is rarely the case…

For example, imagine a bank that offers both banking and insurance to its customers. The bank has acquired the insurance business, which already had an insurance solution. The customer master data is stored in a CRM system. So if we were tasked with developing a customer self-service portal for the bank, the portal would need to call three different systems (CRM/Bank/Insurance), with three different protocols, and three different security schemes, just to get a basic overview of a customer’s engagement with the bank.

A common way to overcome this imperfect setup is to create a new backend in front of the real backend(s) and then design the perfect API for the frontend.

This is known as the Backends for Frontends (BFF) pattern and an example (using our imaginary bank) is shown below:

The Web BFF in the diagram above can expose a simple GET /customers/{id} REST operation that our frontend can call instead of dealing with the complexity of calling and integrating three different systems.

Beside respecting the separation of concerns principle, by separating our presentation logic from our integration logic, we get many more benefits from using the BFF:

  • Call the backends in parallel: We can call the backends in parallel and perhaps respond faster to the end user.
  • Filter the responses: We can remove internal or sensitive data, such as an unwanted customer flag, or unnecessary data that just adds complexity to the frontend and drains battery power when parsing on mobile devices.
  • Transform the responses: We can transform the responses to the frontend into something more usable, such as translating internal codes to something more descriptive. For example, a code in a job field can be translated from SH_CLERK to Shipping Clerk.
  • Enhanced security: We can add extra security in the BFF, such as OAuth2, to protect the unsecure backend solutions, and we can implement a single sign on, so the frontend doesn’t need to deal with different authentication methods in different backend systems.
  • Handle different protocols: The BFF can call FTP, SOAP, REST, GraphQL, and other types of services, but still use a single protocol when interacting with the client.
  • Encapsulate advanced business logic: Issuing a new insurance policy may be a complex operation that requires multiple service calls, but this can be simplified for the clients into a single end point with only the absolute minimum data in a flat structure.
  • Caching across clients: Some of backends may be slow so caching across different clients may be an effective way to deliver acceptable response times to the end users. Moreover, if we need to call usage-based external APIs, it may also be worth caching those responses across clients to reduce the cost.
  • Protect the client from changes to the backend: Changes in the backends APIs need not to result in changes in the UI, the changes can be handled in the BFF.
  • It’s still just code: A BFF doesn’t involve canonical data models, ESBs, or other old-school integration patterns that are complex and time consuming to deal with; it’s just plain code. Moreover, a change in the BFF will not affect other systems, like with an ESB, so it is better aligned with DevOps and microservice thinking.

The main drawback of the BFF pattern is that, at least in the beginning, it can seem like extra work for the frontend team (which should be the ones developing and owning the BFF) but it usually pays back if the underlying backends are non-trivial. Remember that there are no technical restrictions to what language / framework we can use for the BFF; if the frontend team is skilled in JavaScript, they may be more comfortable with writing the BFF in Node.js and that’s perfectly fine.