Are “micro-frontends” just the UI version of backend “microservices”?
Another day, another new front-end solution! Perhaps you’ve heard about the concept of “micro-frontends.” They are a relatively new concept, but they are getting plenty of buzz. You might be wondering if they’re just the frontend flavor of “microservices.” If so, you’re not too far off, but to arm you with everything you need to know to know on the matter, let’s dive a little deeper.
At a high level, micro-frontends are a software development approach that breaks down a monolithic frontend application into smaller, individual mini applications.
The ultimate goal is for each of these applications to be developed, deployed, and maintained independently. As a result, micro-frontends can help to improve agility, flexibility, and scalability. By breaking down the frontend into smaller, more manageable pieces, teams can work in a more independent manner that involves less coordination with other teams or squads.
So… Micro-frontends are just microserves for the frontend?
Kind of. Conceptually, micro-frontends are similar to microservices, but they are implemented at the frontend level rather than the backend level. Microservices can be implemented using different programming languages and frameworks, but at their core, each one should be designed with a purpose to isolate its responsibility from the rest of the technical ecosystem. Oftentimes, one microservice might be dedicated and owned by a particular business unit or individual team.
On the other hand, micro-frontends are typically implemented using the same programming language and framework and can also be isolated from each other for the purposes of a sole responsibility. But they don’t necessarily have to be. In fact, how they should be split is going to differ based on an organization's team structure as well as the structure of their product architecture.
Whereas most microservices interact directly with a corresponding database, most frontends do not. Therefore, one micro-frontend application doesn’t need to have a corresponding micro-service, although it can if it makes sense for the product.
A simple example of a micro-frontends architecture
Let’s say you have a complex microservices architecture where each service is responsible for its own piece of functionality. Your company offers a video streaming service to paying customers. Within your ecosystem, you have a service dedicated to customer accounts and their preferences. You have another service focused on membership billing logistics. And of course, there are other service(s) that are tailored to video management and delivery.
With this scenario, there could reasonably be a micro-frontend for the “billing portal” and another micro-frontend for the “customer preferences portal.” This is perfectly acceptable, but perhaps the UX/UI of your application provides customers some sort of “profile dashboard” where customers are able to manage their billing information and general user preferences in the same interface.
In this case, it might make more sense to have a micro-frontend dedicated holistically to all aspects of how a customer manages their profile. And likewise, there will be other micro-frontends to power other aspects of your streaming application.
You might already be using micro-frontends
It’s common for front-end application architecture to consist of reusable UI components. A larger application will likely have many components, often containing patterns to help streamline typography (such headings, body content, and links), structure (such as grids and general page layouts), and frequently used widgets (such as content blocks, data tables, or form elements).
Many organizations have invested the time and effort into managing their components in a separate library that can be versioned and packaged up for use within frontend repositories. This is a great pattern to start a new product with since it allows for rapid scaling down the line.
In other words, rather than managing all of the frontend UI components along with the application itself within a monolithic frontend repository, they could easily be consumed by a new frontend application that needs to look and behave the same way. As a result, the components are maintained and distributed centrally, and the consumer applications that rely on them can pull them in (and upgrade them when they change or if new components are added).
As a product scales, this type of pattern becomes an obvious and natural progression for engineers to take. If your front-end isn’t monolithic and instead is broken apart into multiple repositories, you’re already employing a micro-frontend architecture.
There’s more to the concept of building a mature micro-frontend architecture than just having multiple frontend repositories — and we’ll get into that later in this post — but don’t let a shiny new buzzword describing an old architectural pattern add to your confusion.
A micro-frontend architecture might be (very) overkill
A micro-frontend architecture may be appropriate when you have a large-scale application with multiple teams working on different features. It can help reduce the complexity of the frontend and improve the overall maintainability of the application. However, just like microservices, it may be overkill for smaller applications with only one or two teams, or even bigger applications with multiple teams that have functional co-dependencies.
When moving to a micro-frontend architecture, there are several infrastructural considerations that need to be taken into account. These include
- How to integrate the different micro-frontends into a single application
- How to handle shared dependencies and data
- How to manage routing and navigation between different micro-frontends
These considerations are important and can become complex very quickly, which results in a technical overhead that might become burdensome. It’s worth weighing these aspects together when it comes to your application to ensure they don’t create more problems than they’re intended to solve.
Infrastructure & security
If you’ve worked in microservices architecture, perhaps you're intimately familiar with the infrastructural hurdles needed to stand up, maintain, and deploy new microservices. This is no different when it comes to micro-frontends. Each micro-application will need to be independently managed in the cloud. Infrastructure as code is highly recommended to streamline these tasks, but the nature of the complexities still remain a reality.
Micro-frontends can also be more difficult to secure than traditional monolithic applications. This is because micro-frontends need to be able to have independent deployments, which can make it more difficult to enforce security policies across the entire application.
Micro-frontends need to communicate with each other in a way that is consistent, efficient, and performant. Simple examples of this are global state management and routing, but can also involve more complex nuances like shared package dependencies (for performance gain) or sharing complex modules that might be too small to be their own micro-frontend as well as too big to be their own shared component.
This can be challenging, especially if the micro-frontends are developed by different teams using different technologies and frameworks.
The beauty of backend microservices is that they can be maintained and deployed independently. There might be occasions where coordination is required to roll out major application-wide updates, but since microservices are built to be isolated, the majority of releases shouldn’t hinge upon other microservices.
Similarly, micro-frontends represent different layers of an application, but they inevitably interface with each in unison to compose a larger cohesive application. As a result, deployments might require more consideration when rolling out features that could cause cross-application regressions (and these aren’t always obvious or foreseeable!).
It’s feasible that a new deployment of one micro-frontend might necessitate an update and deployment to another micro-frontend to ensure working functionality across the entire application.
Orchestrating a micro-frontend architecture
At this point, we have a good foundational understanding of what a micro-frontend architecture is. However, the topic wouldn’t be complete without discussing some of the existing tooling that has been developed to lessen some of the complexities that can come with standing up a micro-frontend architecture.
If you’re familiar with working in a large monolithic architecture, perhaps you’ve come across tools like Lerna, NX, or Yarn Workspaces to help manage a monolithic repository.
Similarly, there are tools out there built for the purposes of orchestrating micro-frontends. This topic is big enough for its own post and thus, this section is only a quick glimpse into the ecosystem. When evaluating technologies that cater to micro-frontends, keep in mind that different orchestration patterns might be more appropriate for your product than others. It’s worth going through provided tutorials or video demos to see what each solution offers at its core.
Bit CLI (command-line interface) bills itself as an open-source all-encompassing “component-driven-development” tool that aims to transform monolithic architectures into distributed micro-frontends. Its tooling enables engineers to work independently without inhibiting cross-team collaboration.
Bit CLI is one of the more mature solutions in the micro-frontends realm. It can do many things, so it’s worth reading the documentation for more details. It is also worth pointing out that Bit has a cloud offering to compliment their CLI tooling, making it easier to get up and running on a mature micro-frontend infrastructure. This might be a great solution for some applications, but tread carefully when introducing new cloud services to your technical infrastructure.
Piral is another “all-encompassing” micro-frontend framework that allows engineers to create modular applications. These applications are referred to as “Pilets” and live within a “Piral instance” using a relatively opinionated, yet predictable architecture. What Piral does under the hood is quite interesting (check out the architectural overview).
Piral is easy to understand conceptually, but getting up and running in a large pre-existing monolith can be a feat, resulting in some trial and error. While it appears on the surface to be a seamless development experience, engineers might also find the documentation lacking.
Webpack Module Federation
Module Federation is a new feature in Webpack 5 that aims to help engineers compose micro-frontends into a single application. Module Federation works by allowing you to share modules between different applications. It can dynamically load code from another micro-frontend application at runtime.
It also has the ability to intelligently manage shared code dependencies, which keeps bundle sizes nice and small in the spirit of optimal performance. In other words, if two or more micro-frontends share the same library (and they almost always will), Module Federation will build the project in a way that won’t download and load a dependency more than once.
SystemJS is a dynamic module loader used to import modern JS module formats and load them at run time, rather than build time (like Webpack). Its orchestration capabilities are not specific to micro-frontends, but it does allow an application to dynamically share independent modules, which is a crucial aspect of a micro-frontend architecture.
Not sure what the best solution is for your needs?
Even though micro-frontends are a relatively new concept, the options above are far from exhaustive. Many members of the open source community are clearly passionate about solving complex architecture problems and sharing those solutions. But we’re still in the early days, and trying to understand every option out there is quite a challenge.
If you’re considering a micro-frontend architecture, our architects are always available to help evaluate your needs and work through an architecture strategy together.
The TLDR on Micro-frontends
Micro-frontends are a powerful architectural pattern that can help to improve the agility, flexibility, and scalability of large-scale software applications. However, micro-frontends can be more complex to develop and maintain than traditional monolithic applications. It is important to carefully consider the pros and cons of micro-frontends before deciding whether to use them for a particular project.
If your application is undergoing challenges or growing pains with regards to frontend scaling and stability, be sure to get in touch with us for a free consultation. Our software architects love solving complex problems at scale and we’d love to work together with you to solve yours!