Skip to content
All services
Service 03 / 03 Available · part-time · B2B

Micro-frontend architecture

Since 2021 I've worked on a platform of 28+ Vue apps living in single-spa and talking to each other in real time.

Engagement
Available · part-time · B2B
Stack
Vue 3 · single-spa · TypeScript · GraphQL · Apollo · SignalR · Storybook · Kubernetes · Azure

Micro-frontends are a tool, not a goal

Micro-frontends make sense when several teams need to work on different parts of the same product and release them independently. They are much less useful when there is only one team and one application. In that situation, a well-structured monolith is usually simpler to build, easier to run and cheaper to maintain.

That is the first question I ask before recommending this architecture: what problem are micro-frontends supposed to solve? If the answer is not about team autonomy, independent delivery or clear ownership, there may be a simpler solution.

Working with a micro-frontend platform since 2021

Since 2021, I have been collaborating with the frontend team working on a B2B2C platform for a catering enterprise in Germany. It is a long-term partnership that has grown into a large frontend ecosystem with about 28 Vue applications running under single-spa.

The applications use several communication and data technologies depending on the problem: GraphQL with Apollo, REST APIs and SignalR for real-time updates. I have also worked on the Docker and Kubernetes setup, Azure CI/CD pipelines and the shared tooling around the platform.

Working on the same system for several years gives you a different perspective from building a proof of concept. You see which boundaries hold up, where teams start creating hidden dependencies and which parts of the architecture need stronger rules.

Where the real complexity is

Boundaries and typed contracts

The difficult part of a micro-frontend architecture is rarely mounting another application. The difficult part is deciding what each application owns, what it is allowed to know about other applications and how they communicate.

I keep those boundaries explicit and use TypeScript to make contracts visible in the code. That applies to shared packages as well as communication between applications. When one application needs another to react to an event, the message format should be treated like an API contract rather than something developers agree on informally.

A shared component library

With about 28 applications, letting every team solve common UI problems independently quickly creates inconsistency. I designed and shipped a Vue component library in Storybook to give the teams a shared set of components and patterns.

The goal was not to centralise every decision. It was to make the common decisions once, document them and make them easy to reuse.

There is more detail in the micro-frontend platform case study.

Independent environments and delivery

Independent applications also need independent development and delivery workflows. On the platform, I used Docker and Kubernetes to create isolated environments for individual features instead of having developers work against one shared environment.

I also worked on the Azure CI/CD pipelines that deploy the micro-frontends. Once you have many independently deployed applications, the delivery system becomes part of the architecture. A good local setup and a reliable pipeline are what make that independence practical for the team.

Communication between applications

The applications communicate through an event bus built on window.dispatchEvent. The browser API itself is simple; the important part is how the team uses it.

I wrapped the event bus in a dedicated SDK package that every application uses. That gives the platform a single, typed communication interface instead of leaving each team to invent its own event names and payloads. When a contract changes, TypeScript can show us which applications need to be updated.

This is all one product and one team, but the architecture still has to work at the scale of about 28 independently deployed applications. The single-spa platform, the shared component library, the Kubernetes environments and the translation tooling all form part of the same system.

Data, caching and real-time updates

Once several applications consume the same backend data, stale or duplicated state becomes an easy source of unnecessary work. A single change can otherwise trigger several fetches, or leave different parts of the interface showing different versions of the same data.

On a related Vue 3 rewrite for the same client, I worked with a typed data layer and targeted cache invalidation. Instead of refreshing everything after a real-time event, a SignalR message can invalidate only the queries affected by that change.

The same approach is useful in a micro-frontend environment: keep ownership clear, make data flow explicit and avoid refreshing more state than the event actually changed. The approach is described in the performance rescue case study.

Keeping a large frontend coherent

With many applications, architecture is not something you define once and then forget about. Small shortcuts accumulate, and a boundary that is ignored often enough stops being a boundary.

That is why the platform relies on a combination of technical rules and day-to-day team practices.

  • Linting and hooks. Strict linting, formatting and git hooks catch many consistency problems before they reach code review.
  • Code review. Reviews are especially useful for things that are easy to miss in isolation, such as imports that create an unintended dependency between applications.
  • Team leadership and mentoring. I lead the frontend team behind the platform and mentor developers working with the architecture, so decisions and patterns do not live with one person.

How I approach a micro-frontend engagement

I start by looking at the problem rather than the architecture.

Do you actually need micro-frontends, or would a modular monolith solve the same problem with less complexity? If micro-frontends are justified, the next step is to define the application boundaries, the communication contracts and the shared parts of the system.

From there, the job is to make those decisions practical: enforce the important rules with tooling, create development and deployment environments that support independent work, and keep enough shared infrastructure in place that the teams do not have to reinvent the same solutions in every application.

The goal is not to create an impressive architecture. It is to have a system that teams can change safely, deploy independently and understand a year or two later.

Related work

Micro-frontend platforms often expose other frontend problems as well. A slow query or duplicated fetch can be multiplied across many applications, and older parts of the platform can become a bottleneck for the rest of the system.

That is why I also work on frontend performance audits and Vue 2 to Vue 3 migrations, usually as part of the same platform work rather than as isolated projects.

I am available part-time, on B2B terms, remotely. Describe your platform and your teams, and I will reply within one business day.

Let's look at your frontend.

Part-time, B2B, remote. I reply within one business day.

Let's talk