What are Microfrontends?

Microfrontends are a way to build large web applications in a modular way. Each microfrontend is an independent solution for a “business concern”, meaning that it is a self-contained, small application which can be integrated into a web page.

Microfrontends are more than just user interface modules, in fact they are a very powerful concept to build complex software in a “vertical” way where deliverable artefacts are aligned with business logic rather than technology. The opposite would be a “layered” architecture where artefacts are aligned with technical concerns such as frontend, backend, database.

But before we dive any deeper, let’s have a look at a real-world microfrontend. On the left-hand side, you see a microfrontend that displays the current weather at a given geolocation. On the right-hand side is the actual, literal code it takes to embed this microfrontend on any webpage. Try it out!

Loading weather data.

<!-- Weather in Aachen, Germany -->
<current-weather
    lat="50.776334"
    lon="6.083706"
></current-weather>
<script
    src="https://demos.lxg.de/current-weather/frontend/main.js"
    async
></script>

As you can see, the web component is delivered by a third-party domain. This is not a problem; in fact, it is a huge benefit of this approach: Teams can maintain their own infrastructure and compose microfrontends in the browser. (That said, there are other microfrontend approaches which rely on server-side or build-time composition.)

You might also wonder what the <current-weather> HTML tag and its attributes lat and lon are. This is a so-called custom element, meaning that we have defined our own custom HTML tag with custom behaviour. This works similar to the better known <video> tag; basically it is a complex element with embedded user interface logic.

Backend for Frontend

It is very important to understand that the microfrontend has a little backend as well. While the actual weather data come from the Open-Meteo API, they aren’t retrieved by the frontend directly. Instead, there is a little backend service acting as a proxy.

This pattern is called “Backend for Frontend”, abbreviated as BFF. Indeed, the web component and the BFF are “best friends forever”, because the sole purpose of the BFF is to aggregate and transform data for the frontend. As opposed to traditional APIs that decouple a backend application from its clients, the BFF decouples the client from data provider backends.

Note that there is no need for API contracts between the BFF and the client-side. In fact, the API structures between them could change with every increment. Advanced APIs such as REST and GraphQL have no place here, because they only increase the complexity of the payload and require the frontend to do transformations. All transformations should really happen on the server side, and the client side should receive only excactly what it needs.

In the example of the weather microfrontend above, the BFF receives a large JSON object with raw weather data. From that data, the BFF selects only the necessary values, transforms them in a way that is easier to process by the frontend, and caches the result for a few minutes. It also performs time/timezone transformations which require some heavy lifting and would only decrease performance if done in the frontend due to necessary libraries and computational overhead.

A BFF is a private service of exactly one microfrontend; it must never be shared with other consumers. As stated above, the data structures between the client and the server can change at any time, therefore creating dependencies on them is bad practice. If functionality needs to be shared between multiple microfrontends, it should either be extracted into a build-time library or into a stand-alone backend service with a stable and properly versioned API.

Building Websites With Microfrontends

Microfrontends can be used stand-alone, but usually they are combined into larger applications, such as a sales platform. In the following graphic, each of the blue-bordered boxes is one microfrontend: The main ones provide search, filter and result capabilities for a flights shop, but even the smaller ones at the top (site search, favourites, shopping cart) are microfrontends in their own rights.

Microfrontends on a page

By “slicing” the website into multiple independent blocks, capabilities can be delivered in parallel. As microfrontends are loosely coupled and expose a clearly defined interface contract to their environment, there is no risk of breaking the platform with this decentralised approach.

Horizontal vs. Vertical Architecture

It is important to note that microfrontends are far more than UI elements on web pages. In fact, a microfrontend is a self-contained full-stack web application which usually, despite its name, also contains backend and persistence functionality. Together with other microfrontends, it is integrated on web pages, which in such an architecture act as mere integration points.

Horizontal to Vertical

This architectural style is called “verticalisation”: Instead of building large web applications in layers that are driven by technical concerns, they are build in full-stack components defined by a logical scope. As such, microfrontends are related to microservices which also are self-contained and part of a loosely coupled ecosystem as well. Even more, they extend the paradigm of service-based decoupling to the frontend of a web application.

The OpenMFE Specification

In order to achieve the objectives of loose coupling and evolvability, we need rules that govern the interoperability of microfrontends without taking away the freedom of teams to build their microfrontends in the best possible way. This is why we have developed the OpenMFE specification which governs how microfrontends need to behave at runtime. It contains general provisions that describe how encapsulation is achieved as well as rules for prerendering and semantic data. Finally, it contains a formalised way to describe the interfaces of a microfrontend in a manifest file.

There are different ways of building a microfrontend-based website. OpenMFE follows the client-side integration approach, meaning that we see microfrontends as web components which are integrated into a web page in the browser. We have chosen this approach mainly for two reasons: First, it allows a team to deliver updates of their microfrontend to the client at any time, without a dependency on a build pipeline. Second, by encapsulating all HTML, CSS, and JavaScript in the Shadow Root of a custom element, we achieve a strong separation of the microfrontend from its environment.

Frameworks

There are different frontend frameworks which are more or less suited for building microfrontends. In our case, however, the best framework is no framework. This may seem strange, but the reality is that the native functionality of browsers has become very powerful over the last few years, and as we don’t need to support old browsers anymore, there’s not much missing! Of course, we use libraries for things like localisation or other purposes so that we don’t have to reinvent the wheel, but we will think very hard before we decide to use a framework like React that adds a lot of overhead in terms of code and client resource usage.

That said, there are lightweight framework with a reasonable trade-off between developer experience and overhead, such as Lit Element.

Curious To Learn More?

If you would like to learn more about the development of a microfrontend, please have a look at our intro tutorial with a step-by-step walk-through of a real microfrontend.