Micro Frontend: A Microservice Approach to Developing Web UIs
There’s been a lot of buzz around the microservices concept lately with quite a few businesses adopting it to get rid of huge, monolithic backends. While this distributed style of building the server-side of web apps is more or less stable in terms of research and implementation, going the same way with the frontend is still a problem for many companies.
The client-side monolith usually stands in the way of integrating new features, introducing new technologies, and scaling separate components due to their tight coupling.
These and other issues have made frontend developers look in the direction of microservices too. This resulted in a new architectural approach to designing the front-end layer of websites and web-based apps — micro frontend. The term was first used in 2016 and since then it has received a lot of attention, and for a reason.
This post will give a high-level overview of what micro frontends are, what problems they solve, and how to implement them. We’ll also focus on the potential uses of this approach.
What are micro frontends?
Micro frontend is an architectural and organizational style (NOT a specific technology!!!) in which the front-end of the app is decomposed into individual, loosely coupled “micro apps” that can be built, tested, and deployed independently. Just like in the world of microservices where the backend is chopped into individual services.
Simply put, each micro frontend is just code for a fragment — a separate feature — of the web page. These features are owned by independent teams, each having a distinct business area or mission it specialized in.
Let’s look at the example of the Instagram web page for a better understanding. For this, we’ll take a profile of a beautiful and fearless Ukrainian Jack Russell Terrier named Patron. After all… why not? 😇
An Instagram web page presented as a set of possible micro-apps
So, where can you possibly implement micro frontends here? First, it’s the navigation bar. Generally speaking, things like header and footer are typical targets for micro frontends. Next, it’s the block with saved stories. And finally, the block with posts that can be developed as a separate service.
Though relatively new, the micro frontend framework is already enjoying great popularity across organizations striving to improve their web development. For example, Spotify — a huge audio streaming company — has been one of the early adopters of the micro frontend architecture. It organizes its development in autonomous end-to-end teams called Squads.
Now that we’ve dealt with whats, it’s time to move to hows. To help you understand how the micro frontend works in more detail, we’ll compare it to other approaches used to develop applications.
Monolithic architecture vs microservices and micro frontends
Imagine you’re moving. Will it be easier for you to pack all your staff into one huge box and take it to a new place or sort things out in a number of small, nicely labeled boxes and move them one by one?
The answer is on the surface.
This analogy takes us to the two different architectural approaches to building a web app — monoliths and microservices (hereafter — micro frontends).
Different architectural approaches
You may remember those “good old days” when an entire program was built in the form of one indivisible unit. Such an approach is named after an ancient word for a huge block of stone — a monolith. The logic is clear. All parts of monolithic systems rely on one another. So, if you want to change something or add a new feature, you may end up with the whole system failing. While outdated, it still exists in rare cases. Yes, we know what your facial expression is right now.
When someone tells you they still use Rails for frontend.
With new technologies evolving and software products getting more complex, the conceptual split of the codebase into two distinct parts — frontend (client-side) and backend (server-side) — became inevitable.
The separation of concerns between the presentation layer an end user interacts with and everything that happens behind the scenes has become the most common way of doing things. It requires two teams of software engineers — frontend developers creating visual elements and backend developers responsible for creating web services, business logic, data access, integrations, etc.
Yet, despite such a division, by its nature, this approach still remains monolithic. The only difference is that instead of one massive program we’ve got two large chunks of code — frontend and backend. Monolith architectures aren’t necessarily that bad and provide a few advantages such as
- easy and fast development for small applications — the design is pretty straightforward with a single source codebase;
- relatively simple testing and debugging — since all code is located in one place, a team can easily follow the flow of a request and find a bug; and
- lower costs in the early stages of an application — there is no overhead either in infrastructure cost or development cost unless you start implementing new features.
The downsides of this approach reflect in
- limited deployment flexibility — you need new deployment every time you make an update to code with teams having to wait if there are a few of them on the project;
- difficulty in introducing new technologies — trying a new technology results in the need to rewrite a large part of — if not the whole — project;
- a single large codebase — a system of code is tightly coupled, complex, and hard to manage and understand when the number of developers grows;
- scalability issues — since components of the project are interdependent, scaling them individually is challenging, causing substantial downtime and increased costs;
- organizational problems — if many teams are working on the monolithic project, each team member must use the same version of libraries and notify of any changes; and
- the high entry barrier for new developers — new team members may find it hard to grasp the logic of the entire project especially if the developers who initially worked on it are not around.
Microservices and their siblings — micro frontends — were created to solve the main issues of monolithic architectures.
Microservices are the architectural approach to building an application backend as a composition of multiple, loosely coupled, and independently deployable smaller components, or services. Each service runs its own process and has its own codebase, CI/CD pipelines, and DevOps practices.
If you look at the picture above, you will see that the monolith backend team gets split into independent teams. Each works on a specific feature of the application (e.g., product service, search service, and payment service) separately.
Communication between the services happens through defined methods called APIs, for example, via a lightweight REST API protocol that involves synchronous request-reply patterns. Another path is to opt for asynchronous interaction using technology like Kafka, which supports events and publish/subscribe communication models.
Microservices gel with the frontend via an API Gateway over the network or via a backend for the frontend (BFF) service. API Gateways provide a single point of entry for a set of microservices while BFF offers a targeted API for each client.
But even with independent components at the backend and all the benefits brought with them, the frontend is still a monolith.
So, here’s when micro frontends come into play.
Micro frontend architecture
The micro frontend architecture resembles microservices where loosely coupled components are taken care of by different teams, but extends the idea to the browser. With this pattern, these are web application UIs that are composed of semi-independent fragments. Also, teams aren’t grouped around a skill or technology, but rather formed around a customer need or use case.
For example, if we take an eCommerce site, features like payment and search will involve two independent teams responsible for end-to-end development, code quality, user experience, and deployment. Each team has its own clearly-defined mission. Say, the team creating the search functionality may have a mission that sounds like this, “Help the customer to find the product they are looking for”.
Micro frontends with end-to-end teams.
So, in projects based on microservices and micro frontends, teams are
- vertically sliced — they develop their features end-to-end from the user interface to databases as there are not only frontend developers but also data specialists, backend engineers, QA engineers, etc., all working on one mission; and
- cross-functional — each member shares their knowledge with the rest of the team.
Moreover, teams can choose the tech stack that fits best for their part of the work. One team can write code for their fragment in React. Another team writes in a new version of Angular. Someone uses Vue.js, for example.
Coupled with associated microservices, micro frontends are called on to solve the problems development teams usually have with monoliths. The approach provides the following benefits.
Better flexibility. Each micro frontend is self-contained, meaning it can be built, tested, deployed, and updated independently. So, if one team is working on a feature and has pushed a bug fix and another team needs to add its own feature, they don’t have to wait for the first team to finish their work.
Multiple, smaller codebases. Micro frontends will have their own codebases, each of which will be smaller in size and more manageable. There will be fewer developers working on a particular part of UI, leading to simpler code reviews and better organization of all things.
Easy app scaling. Another advantage of micro frontends is that each feature can be scaled independently. This makes the entire process more cost- and time-effective than with monoliths when the whole application has to be scaled every time a new feature is added.
Autonomous teams and systems. Each product team and therefore feature can operate with minimal dependency on others, which means it can function even when the neighboring components are down.
The lower entry barrier for new developers. Micro frontends are easier to understand and manage than UI that isn’t split up into smaller and simpler components. So, new players won’t have to spend ages learning the whole code before they start bringing value to the project.
How micro frontend works: Core ideas and integration patterns
As we’ve said before, within the micro frontend architecture, teams are vertically arranged, meaning they are divided by the domain expertise or mission and have end-to-end responsibility for a certain feature. It can encompass one or two microservices on the backend and its view as a micro frontend. Let’s look closer at what this visual element is, how it interacts with other UI fragments, and how to integrate it into the webpage.
Micro-frontend architecture and team structure
A micro frontend can be
- a complete page (e.g., a product detail page) or
- individual fragments of the page (e.g., headers, footers, search bars, etc.) that other teams may use.
If you take a large website, you can split it up by page types and assign each type to a certain team to work on. But there are elements like headers, footers, recommendation blocks, etc., that often appear on multiple pages. For example, a recommendation block may be a part of a homepage, a product detail page, and even a checkout page. Basically, teams can develop fragments that other teams can also add somewhere on their page. But unlike the reusable components, the micro frontends can be deployed independently as separate projects.
All of this sounds great, but both pages and fragments need to be assembled somehow into a single interface. For this, you need frontend integration (see the viz above) that happens via different techniques, namely routing, composition, and communication.
Routing works for the page-level integration — when you need a service from a page owned by one team to get to a page owned by another team. Each micro frontend is treated as a single-page app. Routing can be approached by merely using HTML links. By clicking on hyperlinks, a user forces the browser to fetch the target markup from a server and then replace the current page with the new one.
For cases when a page must be rendered without reloads, you can opt for a shared application shell or a meta-framework like single-spa.
Meta-frameworks make it possible to combine different pages, regardless of the library or framework used, into one whole. For example, the single-spa framework provides a set of solutions such as
- a module loader to load individual pages asynchronously;
- separate wrappers for different UI components to connect them into a whole; and
- APIs for communication between individual applications, subscription to events, etc.
Composition is what you do to the fragments to get them in the right slots within a page. The team that ships the page doesn’t usually fetch the content of the fragment directly. Instead, It inserts a marker or placeholder at the spot in the markup where the fragment should go.
The final assembly is achieved by a separate composition technique. There are two main types of composition — client-side and server-side.
Client-side composition. HTML markup is created and updated directly in the web browser. Each micro frontend can both display and update its markup independently of the rest of the page. You can perform this sort of composition via Web Components, for example.
The idea is to create each fragment as a web component that can be deployed independently as a .js file, after which the applications can load and render them in the placeholders created for them in the theme layout. Web components rely on HTML and DOM API that other frontend frameworks can access and a common way of receiving and sending data using props and events.
Server-side composition. With this pattern, the UI fragments are composed on the server, which means that the client-side receives, in fact, a fully assembled page, resulting in increased loading speed. As a rule, the assembly is performed by a separate service, located between the web browser and web servers. An example of the service is CDN (content delivery network).
Depending on your requirements, you might pick one or a combination of both.
Сommunication patterns between micro frontends
The perfect-case scenario of the micro-frontend framework is when the interaction between different components is kept to a minimum. However, there are cases when micro frontends need to communicate with one another and exchange data. Here are a few possible patterns to make that happen.
Props and callbacks. Here you define a parent component and child components. The communication is set in the form of a tree. Parent components use props to pass the information as functions down the tree to the child components. The child, in turn, can effectively notify the parent when something happens in their state by returning callbacks. This mode is used in React.
Event emitter. In this scenario, different components talk to one another by listening and responding to any change of state of the components they are subscribed to. When a micro frontend fires an event, other micro frontends subscribed to that particular event react accordingly. This is possible due to an event emitter injected into each micro-frontend.
When you need and don’t need micro-frontends
All that said, you may think that the micro-frontend architecture is a silver bullet. Well, it’s not, obviously. As with all approaches, the micro frontend won’t magically mitigate all your pain points. It’s important to weigh all pros and cons to see if this style fits your particular case.
When micro frontend is a good idea
Medium to large projects. The style of building micro frontends is ideal for scaling development and as such makes a good fit for larger projects with multiple teams. Say, if you are working on a large eCommerce site like Zalando, you will benefit from using micro frontends.
In 2015, Zalando – one of the biggest retail players – decided to move away from a monolithic shop system and opt for the microservices for the frontend. They called it Project Mosaic. The approach allowed the company to distribute the work on the main website between a large number of teams which resulted in faster delivery of features and better scalability.
Web projects. The concept of micro frontends isn’t tied to a specific platform, but it shines the brightest on the web. Native apps for iOS and Android are monolithic in their fashion. You won’t be able to compose and replace functionality on the fly.
Productivity-focused projects. Having vertically sliced teams adds up to the overall productivity. But it comes with extra costs and maintenance challenges. If you put productivity first and are ready for overhead, micro frontends can be considered.
When micro frontend isn’t a good idea
Projects with unclear vertical cuts. You need to know the business domain you’re working in. If it’s not clear what team is a perfect match for implementing a particular feature, you can end up with a messed-up work organization, more complexity, and fewer gains.
Small projects. You don’t need to overcomplicate what can be done easily and quickly using a common monolithic approach. That’s the case with small and simple websites. Just because the new style is trendy doesn’t mean you have to use it everywhere.
So, before implementing the micro frontend framework, understand why you are doing this and keep in mind that this style is not for everyone. Yes, this is a trend that is now being actively discussed in the community. Yes, many big companies will come to this architecture one way or another. But all of this is relevant in the case of a bulk application. If the site consists of several pages, micro frontend loses its meaning. It’s already overhead.
Besides that, the architecture has a few more challenges including more frontend code to be created, which often leads to redundancy. Not to mention that micro frontends are complex structures that are difficult to implement and maintain.