A microservice is a largely independent application component tasked with a specific function in a system.
This type of setup has many advantages, such as the ability to write any service in a different technology and deploy them independently as well as performance boost and more. But it also comes with quite a few challenges, including complex administration and configuration.
learning about microservices design patterns is a great way to understand microservices better – more high-level than actual coding, yet specific enough to figure out the inner workings of microservices.
Types of microservices design patterns based on the communication patterns
The direct pattern
API Gateway
Backend For Frontend (BFF).
The direct design pattern
This is the most basic setup for a microservices-based architecture. In this design pattern, a client app makes requests directly to microservices, as shown in the picture below. Each microservice has a public endpoint (URL) the client can communicate with.

In this we have Performance,Scalability,Security and complexity issues.
Since microservices are usually recommended for complex apps, there must be more scalable patterns with greater business capability and the ability to easily support multiple services.
API Gateway design pattern
The API Gateway takes the business capability up a level. As described in the picture below, it provides an extra layer, a single entry point between a group of microservices and the frontend layer. This design pattern addresses all the concerns we just mentioned, by hiding the endpoint of microservices from the public, abstracting references to microservices from the client and reducing latency by aggregating multiple calls.

However, this microservice design pattern is still not safe from scalability issues. It’s more than sufficient when the architecture revolves around one client. But if there are multiple client apps, the API Gateway design pattern may eventually get bloated, having absorbed all the varying requirements from different client apps. Eventually, it may practically become a monolithic app and face a lot of the same issues experienced with the direct pattern.
Therefore, if you plan for your microservices-based system to have multiple clients or distinct business domains, you should rather consider using the Backend for Frontend design pattern from the start.
Backend for Frontend design pattern
BFF is essentially a variant of the API Gateway pattern. It also provides an additional layer between microservices and clients. But rather than a single point of entry, it introduces multiple gateways for each client.
With BFF, you can add an API tailored to the needs of each client, removing a lot of the bloat caused by keeping it all in one place. The result pattern can be seen in the picture below.

It’s worth it to mention that this particular pattern may still be extended for particularly complex apps. Different gateways can also be created for particular business domains. This model is flexible enough to respond to just about any type of microservices-based situation. It’s perfect for continuous delivery of microservice architecture on a really large scale and provides incredible business capabilities.
Does it mean that each microservices-based architecture should use the BFF pattern? Not necessarily. The more complex design, the more setup and configuration it requires. Not every app may require that. But if you want to create an ecosystem of apps, or plan to extend it in the future, you may choose a more complex communication pattern for the sake of future scalability.
For eg,You may have microservices for Customers, Orders, Products, Shopping carts, etc. The microservices expose APIs to be used by the frontend.
However, the data returned to the frontend by the Microservices may not be formatted or filtered according to the exact way the frontend needs to represent them.In that case, the frontend needs to have some logic on its own to re-format these data. Having such logic in the frontend will use up more browser resources.
In a situation like this, we can use a BFF in order to shift some of this front-end logic to an intermediate layer. The intermediate layer is the BFF. When a frontend requests some data, it will call an API in the BFF.
The BFF will do the following.
- Call the relevant microservices APIs and obtain the needed data
- Format the data based on the frontend representation
- Send the formatted data to the frontend
As a result, there will be minimal logic on the frontend. Therefore, a BFF helps to streamline data representation and takes up the responsibility of providing a well-focused interface for the frontend.
Another great way to simplify your backend-frontend relation is by sharing types between them.
The role of a BFF
As we already explored, BFF acts as a simple interface between the frontend and microservices.
A single BFF is focused on a single UI, and that UI only. As a result, it will help us keep our frontends simple and see a unified view of data through its backend.
Will this increase latency?
Now we know that a BFF is similar to a proxy server between the client and other external APIs, services, etc. If the request has to go through another component, it will definitely increase latency. However, the BFF latency is negligible compared to the browser’s high resource usage if it needs to work with multiple services not optimized for the frontend.
Building a BFF allows you to intelligently make batch calls to other backends/ microservices and return the data all at once, or return a more convenient representation by transforming and formatting the data.
This can be very useful for mobile clients on 2G or 3G networks where it can take seconds (or more) to establish the connection.
When to use a BFF for your applications
Like many other patterns, using the BFF in your application depends on the context and the architecture you plan to follow. For example, if your application is a simple monolithic app, a BFF is unnecessary. It will add little to no value.
However, if your application depends on microservices and consumes many external APIs and other services, it is better to use a BFF to streamline the data flow and introduce a lot of efficiency to your application.
Further, if your application needs to develop an optimized backend for a specific frontend interface or your clients need to consume data that require a significant amount of aggregation on the backend, BFF is a suitable option.
Advantages of having a BFF
A few advantages of having a BFF are as follows:
- Separation of concerns — Frontend requirements will be separated from the backend concerns. This is easier for maintenance.
- Easier to maintain and modify APIs — The client application will know less about your APIs’ structure, which will make it more resilient to changes in those APIs.
- Better error handling in the frontend — Server errors are meaningless to the frontend user most of the time. Instead of directly returning the error server sends, the BFF can map out errors that need to be shown to the user. This will improve the user experience.
- Multiple device types can call the backend in parallel — While the browser is making a request to the browser BFF, the mobile devices can do the same. It will help obtain responses from the services faster.
- Better security — Certain sensitive information can be hidden, and unnecessary data to the frontend can be omitted when sending back a response to the frontend. The abstraction will make it harder for attackers to target the application.
- Shared team ownership of components — Different parts of the application can be handled by different teams very easily. Frontend teams get to enjoy ownership of both their client application and its underlying resource consumption layer; leading to high development velocities. The below diagram shows an example of such a team separation along with BFFs.
Best practices to follow in practice
- Avoid implementing a BFF with self-contained all-inclusive APIs — Your self-contained APIs should be in the microservices layer. Most developers forget this and start implementing service-level APIs in the BFF as well. You should keep in mind that the BFF is a translation layer between the client and the services. When data is returned from a service API, the purpose of it is to transform it into the data type specified by the client application.
- Avoid BFF logic duplication —A vital point to note is that a single BFF should cater to a specific user experience, not a device type. For example, most of the time, all mobile devices (iOS, Android, etc.) share the same user experience. In that case, one BFF for all these operating systems is sufficient. There is no need to have a separate BFF for iOS and another for Android.
- Avoid over-relying on BFFs — A BFF is merely a translation layer. Yes, it provides a certain level of security to the application too. But, you should not rely on it more than you should. Your API layer and frontend layer should take care of all the functionality and security aspects regardless of the presence of a BFF or not. Because the BFF is supposed to fill a gap, not add any functionality or service to the application.
Conclusion
And so we conclude our exploration on the types of microservices based on communication patterns. We also explored on each type with the uses of the BFF pattern. With a simple design, we can empower a microservices ecosystem, allowing the interfaces to make a better use of the architecture. Not only that, but it could also make a useful tool to facilitate a migration between the old monolith application and the new world of microservices.