Blog

The state of micro frontends with Vaadin

By  
Leif Åstrand
Leif Åstrand
·
On Mar 4, 2025 10:46:36 AM
·

Micro frontends are an architecture in which the application's UI is modularized so that one part of the UI can be redeployed independently of other parts, thus forming a set of self-contained systems.

There are multiple different reasons for building an application in this way, and there are also multiple techniques that can be used for the purpose. As we will see, some of those work well with Vaadin while other techniques can be challenging due to architectural constraints.

Understanding the possibilities and constraints helps you decide what is appropriate for your application. In most cases, the best option is to not use any micro frontend technique at all but instead deploy the entire UI as a single unit.

Micro frontends help scale UI development practices

A micro frontend application is a kind of distributed system with all the additional overhead that you inevitably get when different parts are isolated from each other. Taking on that additional complexity needs to be carefully evaluated to see if the benefits outweigh the drawbacks. There are three typical reasons why someone might want to have this additional isolation: diverse technologies, independent teams, and update frequency.

1. Diverse technologies

There is a natural kind of isolation between different parts of the UI when it is built using different technologies that are not designed to work seamlessly together. An example of this might be if some parts use server-generated HTML pages that are spiced up using jQuery while other parts use Flow for SPA-like rendering. You might do this as a temporary solution while you're switching from one technology to another. I would define this as embedding rather than a micro frontend architecture since you only have two frontend modules: the new one and the old one. On the other hand, you might also have different technologies in an actual micro frontend architecture for a different reason: independent teams where each team picks their own preferred technology.

2. Independent teams

I would say that the main reason for a micro frontend architecture is to allow multiple teams to work independently of each other. This is similar to the common wisdom that has emerged over the last few years in relation to microservices. And the underlying reasons are exactly the same: making any dependencies between teams explicit and reducing the need for teams to coordinate how they release their changes.

One significant difference is that microservices enable using completely different technologies for different services. In contrast, micro frontends benefit from using the same core technologies throughout to ensure a consistent UI and preferably also so that the end user doesn't have to load multiple different JavaScript frameworks to use the entire application. Just supporting multiple independent teams can be handled with a modular code base that is still built and deployed as a monolith.

3. Update frequency

The last reason to consider the micro frontend approach is to control user interruptions better when updated versions are deployed. It is useful for a development team if their changes can be deployed to production as quickly as possible to keep feedback cycles short. If each redeploy may have even a small impact on active users, and there are many independent teams making frequent changes throughout the day, then the amount of disturbance to users could become significant. If each part is deployed independently without affecting users interacting with other parts of the application, the overall impact can be significantly reduced. While this can also be achieved with a true zero-downtime deployment approach, it often introduces additional complexity to the setup.

Independent parts increase the risk of conflicts

There are different approaches to micro frontend development depending on the application's trade-offs.

1. Shared library

The easiest way to get many of the benefits of a micro frontend architecture is to build separate applications that look and behave in a consistent way. From the user’s perspective, the end result feels like a single application, with only a slightly slower page reload when navigating between distinct apps. This approach avoids conflicts between the distinct apps because the state is reset every time the page reloads.

The natural way of ensuring consistency across applications is to:

  • Implement a single sign-on solution.
  • Build a common base theme.
  • Maintain a unified top-level navigation structure.

These shared concerns can be facilitated through a library used by all applications. While there may be minor inconsistencies if the library is updated but not yet adopted across all applications, this is manageable since updates to the shared library are typically infrequent.

2. Common shell

The inverse approach is needed for a fully integrated result without any noticeable seams during navigation or shared library updates. This means that there's a common shell application that loads and renders the individual child components directly in the user's web browser. The shell application can dynamically adopt new versions of the sub-applications without needing to be redeployed.

What this means is that all the sub-applications must be compatible with each other since the web browser doesn't offer complete isolation between parts loaded in the same browser tab. All it takes is one conflicting global JavaScript variable or accidentally matching CSS selector to cause issues with some other part of the application. This also complicates frontend dependency management with JavaScript libraries that are registered in the global namespace and will thus cause problems if different sub-applications use different versions of the same library. One particular example of this is Web Components since each custom element name can be registered only once in window.customElements.

3. Iframe

There is also a third way, which is to use <iframe> elements for isolation. This is usually not a good approach due to the way the frame will also crop rendering for modal UI elements such as dialog windows or dropdown menus. There might still be some cases where this approach is suitable, but those are rare and not significant enough to justify considering it as a generic solution.

Module federation is limited with Vite

Vaadin's UI components are Web Components and thus susceptible to issues with duplicates unless very carefully managed. A Vaadin application using a dynamic shell application for micro frontends would have to use a shared set of components that are defined as part of the shell application. Sub-applications can still define their own custom elements as long as they use unique names – sharing is only needed for common components with generic names, such as <vaadin-grid>. The common components can still be downloaded on demand in the browser, but the set of available components and their version numbers must be fixed when the shell application is built. Additionally, the task that builds the frontend bundles for the sub-applications must take this into account so that the sub-applications don't try to load any common components on their own.

Managing all of this by hand becomes challenging for any application that is big enough to benefit from a micro frontend approach. There is a concept named module federation that promises to take care of this automatically. The bundler of the shell application creates a manifest of all the modules that it includes. This manifest can then be used when bundling each sub-application so that its frontend bundle will load any common module from the shell application's bundle instead of including it in the sub-application bundle. It’s like .dll files but for the web.

The concept was initially implemented for the webpack bundler tool that was used in Vaadin 14. Newer versions of Vaadin have switched to using Vite as the tool for managing frontend bundles. Vite has a more modern approach and is, in general, easier to use. Still, some more advanced features, such as module federation, have not yet reached the maturity level that was available with webpack. This means that it's currently not practical to build micro frontends with a common shell application approach with Vaadin, whereas a shared library approach remains a viable solution.

Vaadin's recommendation is to use a shared library

The easiest way of scaling the development of a web application is to split up the code into separate modules while still building and deploying the whole application as a monolith. If this is not possible for reasons such as redeploy frequency, then a micro frontend architecture is needed. Out of the two commonly used approaches, the limited module federation support for Vite means that a shared shell application is not a viable solution for Vaadin applications. Instead, we recommend that those who need micro frontend capabilities for Vaadin build and deploy fully independent applications and use a shared library to ensure consistency between those applications.

What’s your take on micro frontends? Join the discussion in the Vaadin Forum!

Leif Åstrand
Leif Åstrand
Leif Åstrand keeps an eye on the overall architecture of the Vaadin platform. He knows a thing or two about how Vaadin, Web Components, and the internet works.
Other posts by Leif Åstrand