Transcript
Luca Mezzalira: Imagine this, 10 years ago, I joined a team of people that were trying to revolutionize how you consume live sports in general. People were calling us the Netflix for sports. That was amazing. First year, we deliver our monolith: backend, frontend. We targeted roughly 10 platforms. The vast majority of our customers were watching content on living room devices. We have several set-top boxes, console, web, mobile, you name it. The challenge arose after the first year we launched, massive success in Japan, started to have a lot of rights holders that were asking us to have them in our platform. The problem is, we were working with external companies, and we wanted to internalize everything. Imagine your CTO is coming to your desk, telling you, “Listen, so you know that now we are working with all these people externally, all these companies. Now we need to internalize everything, and we need to scale quickly”.
I was the second person hired in the company. As you can imagine, if it’s difficult designing an architecture, think about designing an architecture for people that you don’t have. For the backend, I have a clear path, I just read Sam Newman’s book. It seems that microservices is a good fit, so no problem. For the frontend, I had a ton of experience that I started back in the days with Flash. How many of you have heard about Flash? Everyone thinks that it’s slow, it doesn’t work. I always work with Flash on embedded systems. I put on a Ducati motorbike, I put on a soda dispenser, and it was super sleek. As every time, if you don’t deep dive into the language and the runtime and everything, it’s difficult to get performance out of it. In frontend, I have done a lot. I’ve done a lot also in the backend. The challenge is, how can we scale the frontend?
Very often, people think that we take a website like this one, like an e-commerce, and then we say, we have this area, let’s say, components. We break it apart. We have micro-frontends. Yes, done. Not quite. That’s the problem, because the reality is we are back to design architecture, finally. Many people are thinking, yes, I’m designing the next project. I’m using Angular, or React, or Redux, or whatever it is. Big spoiler, you’re not designing anything, someone else designed it for you. You’re just assembling libraries in order to work with specific decisions that were made by someone else. That’s not the case with micro-frontends, we are back to architecture.
I’ve done quite a lot of talks in the last 10 years on micro-frontends. I wrote a book. Also, I followed a lot of teams. Roughly, in the last four and a half years in AWS, 100 teams, internal and external, that I followed. I’ve seen a lot of different implementations. We need to start first to be on the same page, because that was a definition that I had to create for the first time that I introduced this concept to roughly 45, 50 developers. They were staring at me saying, but this guy knows what he’s talking about or not. Imagine that back in the days, in 2015, when I thought about this solution, there wasn’t the term micro-frontend.
I walked in a room and I had to explain to people that, yes, you know everything that we have done so far, we’re not going to do that in a way. Who is doing that, asked the CTO? I said, no one. Or, better, there were a few companies, but not at the level that I wanted you to reach. Therefore, I had to coin a definition. This definition is now the definition of micro-frontends, so many people are referring to that. It’s a technical representation of a business subdomain, they allow independent implementations with the same or different technology. They should minimize the code shared and owned by a single team. During this presentation, we are going through all these key points that are highlighted in blue, and we are going to see who is responsible for what and how we should tackle them.
Technical Representation of a Business Subdomain, and Independent Implementations
Let’s start from the first part, a technical representation of a business subdomain and independent implementation. I’m a huge fan of architecture. Domain-driven design was, for me, one of the key aspects when I’m thinking about the design, because they have such a nice way to divide a system in multiple chunks and categorize that. You can have like a core domain. You can have a supporting domain. You can have generic domain. You can assign properties to them. I use that heavily for the backend of my system. We ended up having 250 microservices with a team of 550 techies spread across Europe. It was a sizable system. I used that also for frontend. That’s why there is a subtle difference between micro-frontends and components. Not very subtle, as you will see in a moment.
That independent implementation is the key thing. We are optimizing here for what? For fast flow. That, for me, was the key aspect. Let’s try to understand first the difference between a component and a micro-frontend. Let’s assume that you’re building a component. I thought about the most common component everyone knows, a button. I create a new button for the design system.
The first thing that I expose is a property called LABEL. We start to use that. Then the product team says, it’s super amazing, your button. We want to have also the possibility to add an icon, so let’s add the icon. We expose another property that is icon. Then we start to gain more traction, we want to change the border color. We want also to do different rollover animations, so we expose also that capability. We want to auto-size dimension because we have now the possibility to use this button in multiple portals, in multiple countries, and with multiple languages.
Finally, we want to use for forms. Therefore, it has to be disabled by default because it’s how we want to start till all the mandatory fields are filled. There is a tiny problem here, the button itself is just exposing a bunch of properties, but they don’t know how they want to operate. It’s the container of the button that knows how it should use that specific component. The knowledge, business domain, is owned by the container of a component. What we are optimizing here is for usability. I’m a huge fan of Neal Ford. You don’t have to take my point of view on this, but probably his for sure, that reusability is a form of coupling. Because the reality is, now we want to have this system reused across all the different parts. We designed a system we will see later. It’s not a bad thing, but we need to be careful on how to think about that. Definitely a button is not a micro-frontend.
When we think about micro-frontends, we think about a few characteristics. First of all, is encapsulating its state. If you’re thinking about, let’s use a global state between micro-frontends, wrong answer. The reality is you don’t want to have that, otherwise you are coupling multiple teams. That’s the first problem we have. Second one is context aware. I don’t have to explain to a micro-frontend how it should behave. They just need like an ID for a product ID, or it needs maybe the token. That’s it. Sometimes not even that. It can operate for itself. It defines clear input and output. API contract first, that we discuss a lot on the backend, is valid also here. I want to know, without bothering other people and other teams, what I can use, what events are coming out from these micro-frontends, and what I can interact with.
Last but not least is less extensible. That doesn’t mean not extensible at all. There are some micro-frontends that are designed in a way that could work in multiple views, fine. It has to be designed carefully with this definition in mind. When I was writing the second edition of the book, I was thinking, how can I provide something tangible that people can take away? I started to create a lot of heuristics. Because after seeing hundreds of teams worldwide that are falling every time on the same trap, I started to think about, let’s try to provide some heuristics to explain how to think about that. First of all, a good micro-frontend reduces the APIs that are exposed to the container. Sometimes you have literally one API, maximum two APIs or properties, for instance, an event emitter that is injected and stuff like that.
Second thing is, are context aware. We said that. The state lives inside the micro-frontend, not outside the micro-frontend. Third, don’t optimize for reusability at all costs. Your goal here is not reusability. Your goal is fast flow. You are designing the distributed system mainly for your organization structure. People at the end don’t care. If you go to amazon.com, this is a micro-frontend website. Do you care that it’s a micro-frontend or do you care that you want to buy the next laptop or whatever it is.
Finally, micro-frontends are more coarse grain than components. If you start to see that your view has 25 runtime micro-frontends, you are dealing with, to a certain extent, a distributed monolith. You have a lot of components that are loaded at runtime, with all the drawbacks of a distributed monolith. The other important thing is, micro-frontends, boundaries are not forever. If you imagine any company that is designing, and this is not only micro-frontends, you can say the same for distributed systems. If you design today the boundaries, what is today a core domain, can become a supporting domain later on, or vice versa. Because the business is evolving, and luckily for us it’s evolving because otherwise, A, we are out of our job despite AI. Secondly, it would be quite boring doing only keeps the lights on for every single part of the code that we are writing. Therefore, we need to reassess that part. It’s extremely important.
Organizational Benefits
There are obviously some organizational benefits. As I hinted before, we’re not designing distributed systems only for technical benefits. We can scale independently certain parts. In the case of micro-frontends, I can cache a micro-frontend for longer because maybe the content is more static in certain parts of the application. In others, instead, I want to have a very fast flow. We stressed out this implementation when I was working with Formula 1. If you go to the new website of Formula 1, formula1.com, they started to use a different level of caching, thanks to this approach on micro-frontends. Also, on the organizational part, there are some benefits.
First of all, you can start to have incremental upgrades. If a team works in a core subdomain and starts to have all the people very close, starts to have a fast iteration because the core domain is the reason why you exist as a system or as a company, you start to have a very fast feedback loop that you want to create. Equally, on another domain that isn’t required to change that often, if you think about in a website, the FAQ part or the contact us part, how often do you change in a year? Twice, maybe? Maybe less? You can definitely start to decide that part. Moreover, you have also incremental, so you don’t have to switch to micro-frontends in one go. How often you would say, yes, this is really spaghetti code. In reality, we would like to rewrite the entire application. You go to the CTO and say, listen, I need 24 months to rewrite everything. How often do you have a yes from the CTO? I never had it.
Instead, if you say, listen, we want to incrementally update our system, so maybe we can start with one page, and then in a month’s time, it will be three pages. Then at the end of the year, it will be the full website. This is something that lands very well with the C-suite because you create value for your customers as well as for your business. There is a decentralization part that is essential. There were quite a few talks about decentralizing the architecture decision and also the decentralization of the tech side. The reality is that here we are talking about people.
If you think that to onboard in a journey or moving to any distributed system without decentralizing how you are operating, then I’m sorry, you’re going to find a lot of friction. Team cognitive load. I had every other week one team joining the company, moving from 15 techies to 550. I can guarantee you that with this approach, we started enabling them to produce code in production and release code in production in a month because they have very narrow things that they need to understand. Slowly but steadily over the month, they started to understand the entire system. Finally, bear in mind that you are not scaling only the technology but also the organization. Organization, engineering culture, and architecture goes hand in hand. There is no way that you can change one part and the other two won’t be affected. Either it happens intentionally or unintentionally, but it happens.
One thing that I want to highlight is the year that Conway’s Law was coined, 1967. It wasn’t recognized until late the ’70s. Because at the beginning they said, “Melvin, what are you talking about?” The reality is, this is so true. There are certain decisions that completely affect how you’re designing your system, and the organization is one of them. If you think about that, you can either design an architecture that enables your organization to thrive or you can design an architecture and you adopt the organization in order to enable the architecture to work. It’s very important that when we think about decentralization that we look in the past. I work in a situation like that, where tech leadership set up the platform team, security, architecture, whatever.
Then, on the other side, they select certain technologies, patterns, you name it. Then they throw on the other side of the fence, where I was, team A, B, or C. The team were growing organically. The communication wasn’t controlled at all. There wasn’t co-location on intents or stuff like that. It was like, we need another team, let’s spin up another team. Then if that team was in another time zone and has to collaborate constantly with another team, maybe the first team was in India and the other one was in Canada. Obviously, no one thinks about, yes, but we create friction in the communication. That is exactly what happens.
If you don’t think about how you organize your teams and co-locate the team and trying to figure out a way that they collaborate together, surprise, it’s not going to work very well. In recent years, we started to see the idea of team topologies. The idea is very simple. We start to focus on value-stream teams, so stream-aligned teams, those are those: catalog, onboarding. Those teams are responsible for writing the code that goes to production and generate value for the users. Obviously, as we all know, a system is composed of a bazillion things. We have security, observability, and all the things that we all know. We have also some complicated subsystems, think about the data. Every team doesn’t really need to know how a data lake, or a data mesh, or whatever other data architecture you want to use works.
The only thing that they care about is, I pass this data in this way in either an object storage or I expose a specific API, whatever they decide to have. The data science team enables or facilitates the integration of this stuff to the stream-aligned teams. Then we have the platform team that provides the foundational part for the company, and is used as a federated service. For instance, if you imagine, I want a queue, I ask for a queue, they give me a queue, or I’m a subservice, depends how your model is. Most importantly, we have enabling team. Cross-cutting concern. Think about security, think about developer experience. In my opinion, I would also add architecture.
Platform Team Responsibilities
I want to drill down into platform responsibility because very often people don’t realize that in reality we need platform engineering also for micro-frontends, or in general for frontend. In a monolith it is easier to a certain extent, but for micro-frontends it’s slightly different. I want to share with you what I have seen implemented in several companies that successfully implemented micro-frontends at scale.
First of all, we are talking about this area here. Also, developer experience. Platform teams is usually the one that you spin up at the beginning and is generating that foundation. You can call it tiger team. You can call it core team. I have heard a bazillion names around that. I call that in order to align with the other platform engineering practices maybe you already have in the company. The problem they have is that in every single architecture that I’ve encountered in the last 10 years, and I’ve seen quite a lot, we always touch four points, what I call the micro-frontends decisions framework. This is the foundational part that no matter what, you need to define intentionally or not inside your micro-frontends architecture. You need to identify what a micro-frontend is, compose it, routing, and communicate. Those four points are always there. It’s server-side rendering, client-side rendering, edge-side rendering. You always have to think thoroughly about those four points. Let’s start with the first one, identify. There are two ways.
Either you have a horizontal split, that is what you see on the left of this slide, with header, product details. Or a vertical split, where you have one page or group of pages. I’ve seen messed up architectures with both, so don’t think that one is better than the other one. It depends on the reason for selecting one or the other. Usually, if you have a large team and you have a lot of domains that might work in multiple areas of your website, you will go with a horizontal split. Usually, I discourage you to start with that.
On the other hand, if you have clarity of what you want to have and you want to have a more mild approach with micro-frontends, you go with a vertical split, because it’s more or less having a modular monolith. You just divide in pages or group of pages your website, you share a bunch of components at build time, not runtime, and you go ahead and build this stuff. They are not mutually exclusive. In my previous job we had, for instance, my account that was a combination of user details, payment methods that live in two different domains in our world, and therefore we needed to aggregate them in a single view. You can say in certain situations I will go with horizontal split, in certain others I will go with vertical split. No problem.
The composition part is another interesting one. Usually, I will pick client and server composition. There is a reason why I’m not talking about edge-side composition. At the beginning, if I would have done this talk a few years back, I would talk about edge-side includes, and maybe some compute on the edge, stuff like that. The problem is I’ve followed a lot of customers worldwide. Apart from some, majority of the time they were working with one or two regions in the cloud, sometimes three, but rarely. Data has gravity. If you have data that is in the data center in London and you have a request in Australia, even if you have compute that is rendering your website in the point of presence in Australia, the data has to be fetched from London. You have some optimization, but the developer experience for working on the edge is not as great, and you don’t have all the capabilities usually, especially if the compute is running on the point of presence of your CDN that you have in a region.
Therefore, it’s better that you leverage cache in that case, or you use other techniques like in modern frameworks like Next or Astro, that you can use server islands or React Server Components. In general, ideally, you don’t render on the edge. In client-side composition, you usually have what I call an application shell, the dotted line of this diagram, where you load one or multiple micro-frontends. Usually what I recommend, even if you have a horizontal split in this case, you create what I call a meta shell. Basically, it’s nothing more than the shell will load a domain that could be my account, as I was saying before, and then the meta shell knows what it has to load.
In that way, you simplify how the application shell that is owned by the platform team will work, and you can change independently the rest, so you don’t have dependencies with other teams. Same thing on the backend. The backend, it really depends how it works. If you have a server-side rendering approach, you can do server-side rendering for every request, or you can do a composition layer, and you have a bunch of microservices that are doing server-side rendering independently, and you compose basically the output of those microservices in a single page. That is a technique that was used back in the days by Zalando, that is fashion e-commerce. I have a few examples that are available online. The other thing is when you selected the composition, you go to the routing part. The routing part usually is in the application shell for both. Easy.
Finally, communication. As I said before, state management, shared, no thanks. What we want to have in horizontal split, is event emitter, custom event, reactive streams. Usually, the question when I show this slide is, which one do you recommend? My preference goes with event emitter, and I explain why. Reactive streams, I’ve seen a few teams implementing that, and there is confusion from frontend developers on reactive programming. I wrote a book on that. Trust me, there is a lot of confusion around how to use a stream. Custom events have a massive problem that are bounded to your DOM. If you imagine you have your tree, you have one micro-frontend that is communicating on the other side of the tree. You need to bubble up the event up to the window. The other one has to listen to the window and then react to that.
The problem is if someone during the propagation of the event intercepts the event and blocks it, good luck on finding and debugging the problem. Event emitter democratizes everything. Event emitter is completely unaware of the structure. It’s an event. Everyone in frontend is used to working with events. It’s nothing more than an array. If you see the implementation of an observer pattern, it’s just an array that you register for an event, and when there is an event emitted, you just go through the array and say, this is the event happening. If you’re interested, you react. If you’re not interested, you don’t care. Easy. Either you work with horizontal or vertical split, you need to share ephemeral data, or more important data, for instance, a session token. Session token depends on the security posture. It can be a local session storage, not very secure or better, not the best preference in general for security teams.
Cookie is better because you have slightly more control compared to the local session storage. I have seen, especially in finance, customers that are using web workers instead, and they’re storing memory there. What it means is that basically if they try to re-access the website after a while, it might be that the web worker expired and therefore the token isn’t there anymore. They need to re-authenticate. It’s exactly what you want if you are building a bank application, whatever it is. It’s not a big deal for them. In other cases, if you are in e-commerce and you really want to have a sleek user experience, you usually tend to have cookies. Usually that’s how it works.
A few considerations. The application shell that should be owned by the platform team or the core team should be as vanilla as possible. Very often, I’ve seen customers that are using React for the application shell, but then are using Angular or Vue or other stuff. That could be a challenge to handle. Don’t set yourself up for creating runtime errors, because runtime errors might be mitigated by a bit of scope creeping and stuff like that. When they hit, they hit hard because it might work in pre-prod but not in prod. Secondly, should be context unaware.
If you find yourself needing to change a micro-frontend, and also, you need to change the application shell, then go back to the whiteboard, because the boundaries are definitely not well defined and the domain is leaking. You expose the initial configuration and not much more. Very often, when you have a client-side rendering application, the first thing the client-side rendering application does is fetching an API in the context. I’m in Vietnam and I’m using this currency and stuff like that. It’s everything related to that. Finally, it should be responsible for routing and composing. It should be extremely lightweight in general as a rule of thumb for every application shell.
Which Library/Framework Should I Use?
At this stage, you will say, perfect, now we understand how to design micro-frontends. Now we’ll go to the meaty part. How do we design that, or which library and framework do we use? This is like the favorite things that developers have. They immediately jump straight into that. We are using the latest version of Vue. The problem is that it usually works in this way. I have the developers pitching this idea, and this is me. It’s a challenge. It’s a mindset shift, mainly. The architects would say, it depends, and you are done. That’s usually my rule. I’m very pragmatic. I prefer to, instead of only saying it depends, understand one thing.
This is the question you need to answer, what do you need to express inside your architecture? I’ll give you a concrete example. I was in a meeting with a team, the engagement was me saying, listen, we would like to see if Module Federation is the right way for building micro-frontends. I said, fine, let’s hear what they have. They started to pitch me all the technical stuff that they are doing. They had multiple frameworks they need to support. They cannot control which framework or enforce which framework every team is using because some teams were external. They also have to have the same framework but different versions. Quite a lot of strong things. They started to ask, but what are the parts that you can influence? “We are the platform team and therefore we need to create something that doesn’t require us to maintain for too long because we are a small team. There are too many other teams that are working on that”.
I said, listen, but if you are telling me you cannot control the dependencies, they already have, and surprise, in 2025 it’s normal, there are still libraries that are appending themselves inside the window object. You cannot do scope creep because you cannot say, I append inside a specific scope because not even the bundler is capable because they are trying to append themselves into window. It’s a problem because if I have the same library with a different version, one overrides the other one based on how it’s loaded. We have a huge problem. I said, listen, you are a B2B business. You have a B2B business. The only way to retrieve this information is through your portal.
At the end of the day, you don’t care about SEO or organic SEO, whatever it is, just put an iframe, that’s it. Done. How hard it sounded was when we started to list all the tradeoffs of the different options, it was the safest way for them not being on-call overnight. I hate in general suggesting iframe because that means that they really cannot do anything. Unfortunately, in that situation, the context requires extreme measures. In other situations, usually they have control on the frameworks, they have control on how to handle specific things, and therefore we can go with the more modern approach. Unfortunately, again, it’s not the framework that you need to select, it’s the context that you need to understand.
Developer Experience
Developer experience is another thing that very often is forgotten. You don’t have to take care of it immediately at the beginning. You will need to take care of it during the journey. Try to create guardrails over time. I’ll give you an example. One of the problems with micro-frontends is that very often you have teams that start to add library, library, library. They forget about tree shaking, and they start to have the final bundle that is hundreds of kilobytes, it’s not megabytes, I’ve seen also that, of final bundle. If instead you create a shift-left mindset, what I was doing in my previous company, we basically defined what was the size of every single micro-frontend. Every time that the developer was opening a PR, we were triggering a Lambda function with Webpack or Rollup, we were building the micro-frontend and checking that they were inside a threshold of 20%. We basically automated the performance or the budget size of our application at the very first moment that we can intervene with the developers. That was when they opened a PR.
If they exceeded that threshold, they had to justify why they wanted to do that. I can guarantee you that we picked a ton of mistakes made by the developers just because they forgot a configuration or they used a library improperly. Updating shared libraries, that is another question I have every time. How can we update the shared libraries without coordinating everything? Depends how aggressive you want to be. Dependabot is your favorite tool. Dependabot is basically a tool that you can configure, and overnight you just run through all the libraries, despite if they’re monorepos or polyrepo, and you just say, there is a new design system. You bump out the version, you open a PR, done. I had some customers that were more aggressive, they literally merged also the code.
Definitely after developers cloned the project, downloaded the latest things, pulled them from git, and nothing works. It’s up to you how you want to handle. Maintain the required security posture, security scan. I think this one is quite clear. Any other architectural characteristics that you can’t shift left, try to think about that. You cannot design a distributed system from an architectural perspective if you don’t think about guardrails and automation. There is no way it’s going to work. Another thing I started to see a lot of adoption is Backstage. It’s an open-source project from Spotify that is a centralized place for creating templates, documentation, and so on. This one is something that I’ve seen customers implement across all the distributed systems, from frontend to backend. They can download a template with micro-frontends. They already have everything there so they just need to write code and that’s it. Easy.
Deployment
Now, deployment. This one is probably one of my favorite parts. For me, deployment is one of the most important things you need to think when you are designing a distributed system. Because, yes, you have smaller artifacts at the end, no matter if they’re backend or frontend, but there are a few characteristics I want to have available.
First of all, I need to think about an incremental deployment, no matter what. Frequent deployment. I want independent deployment. If I coordinate with other teams, every single time, sometimes it happens during the year when you are releasing a new design system and you want to have an entire application you need to coordinate. If I have these three characteristics on frontend and backend, I’m a happy camper. How do you do that in frontend? Backend we know. We have done on microservices bazillion of times. In frontend, you have no idea how often I’ve seen companies that implement their own solution. I said, this is a problem that I cannot tackle alone. I need to take the most prominent names in the micro-frontends community.
Therefore, I work with Joel, that is the creator of Single-SPA, Zack that is the creator of Module Federation, and Matteo that is the creator of OpenComponents. Three of the most adopted frameworks on micro-frontends. We said, listen, I have an idea, but I don’t want to do it alone. I want to have a working group that we start to socialize the idea. It took roughly 10 months in 2022. What we came up with was a JSON schema, the most simple thing.
During the 10 months, we moved from, let’s create a plugin for a framework to let’s create a JSON schema, that’s better. This one is extremely simple. We have a unique ID, unique identifier, a micro-frontend URL where you can find your micro-frontend, a fallback URL, if you work with multiple CDNs. Metadata, we decide to have integrity and version because usually they are the most important things. Then, extras. There, it can be framework specific things like Module Federation. If you check Module Federation 2, they created a manifest JSON, because it’s heavily influenced by this. You can have, I want to show this micro-frontend only if you are an admin or only if you are in this specific bucket, you can handle it in the way that you want.
Then, obviously I was thinking, but if I have two requests, where I can find my micro-frontend, it means that it’s a network request. If it’s a network request, I can play with canary release and blue-green deployment. Hence, there is an array here. It’s not a unique object. I can have multiple versions of the same micro-frontend. I have just to add the deployment object, that’s it.
This schema is available today, this URL, github.com/awslabs/frontend-discovery, in AWS Labs. We decided to open source it. If you want to check and contribute, feel free to. It’s something that started to be adopted not only from us, because no one was thinking on the idea of discovery service like we have on the microservice world, but for frontend. Obviously, I wasn’t happy. The reality is, when I was thinking, Matteo, that was the creator of OpenComponents, he’s working with me in AWS. I was designing these things. I was like, let’s do a sequence diagram. The more I was thinking about that and trying to apply in different use cases, this part here was always the same. It was what we call in AWS the undifferentiated heavy lifting. We have a service, it’s called micro-frontend discovery. In the database, we just retrieve what version we need. Then we send to an application shell, either server-side, client-side, edge-side, doesn’t matter.
Therefore, I said, “We’re here. We have some time to spare. Let’s work on the frontend discovery service”. We created this open-source solution that is available here. It’s open source also, the reason being that if you want to take inspiration from, if you want to use on-prem, or another cloud provider, whatever, you can. The code is there. We just explain how it works. Currently, we have quite a few customers that are implementing that in their production environment.
The idea here is to use something that enables you to be plugged in every single CI/CD, it doesn’t matter if it’s GitHub Actions, it’s Jenkins, or whatever you have. Because we expose a bunch of APIs on the backend that you can use in order to say, I want to deploy a new micro-frontend. I want to have a canary release with an incremental upgrade of the version of 10% every minute. The system behaves that way for you. It will assign a cookie to the person, so it creates stickiness during the experience. The rollback is literally, sorry, 100% of the traffic on the old version. That is your rollback strategy. If you start to think about rebuilding stuff like that, that is not the case. The only thing that you do is just literally telling the system where you can find the entry point of your micro-frontend, that is either HTML or JavaScript. Completely up to you.
Value-Stream Responsibilities
Let’s move into the value-stream team responsibilities. We are here in the diagram. First of all, this one is the most hilarious thing that I read about micro-frontends for the last 10 years. We are going to use micro-frontends because we can use whatever library or framework we want. Thoughtworks, rightly so, in the Technology Radar of 2017, is called Micro-Frontends Anarchy Antipattern. Because what they realize is if I start to have different versions of the same framework or different frameworks in the same application, they are basically penalizing the user because it has to download way more JavaScript than is needed. I usually say micro-frontends are not a playground for developers. We’re not here for building a monster or Frankenstein architecture, as I heard several times, and have fun with different technologies. That’s not the purpose. We are here to help our customer and our organization to achieve certain goals. Every line of code matters.
Second and most important thing is, minimize the code share. This one I was literally grilled for a month about that. I was walking out from stage with people saying, Luca said that we can duplicate everything, but he doesn’t know about DRY or the KISS principles, stuff like that. As you can see, I’m not very young, so I have seen quite a few stuff. We need to switch our way to think in optimizing for fast flow, and therefore we need to think about that. Luckily for me, I’m in a good company. Sandi Metz, in a talk, said that duplication is far cheaper than the wrong abstraction. I was a developer for several years, probably more than a decade. During that decade, the most amazing thing that triggered me every time, it wasn’t always implementing a new feature, it was doing abstractions. Because now I abstract this, and the entire company is going to use that. Unfortunately for me, it was a majority of the time where two or three people top, that were using that library.
Then, the other nice thing is what we call the diamond antipattern, that they started to basically build an abstraction on top of my abstractions. When they do a breaking change, they couldn’t update the library, because they were on top of the library that I created for the first time. Then, suddenly, having an abstraction library wasn’t that smart. Therefore, I came up with some rule of thumb. You tend to reduce external dependency, that is the goal of micro-frontends, not eliminate, reduce. Design system, great idea. Logging library, great idea. Not everything. I have seen, for instance, a very large American e-commerce, that decided to go extremely granular and externalize a lot of dependencies. They spent six months refactoring that code. Optimize for fast flow. That’s the other thing. This is our primary goal when we are designing micro-frontends.
Last but not least, embrace a lean mindset. We don’t have to analyze every single bit of our decision. There are decisions that could be taken lighter, what we call in Amazon the two-way doors decision. We go with that decision, for reverting back, it takes one day of work. Fine. We leave it at that. Therefore, you try also to take a decision, not taking every single bit, you want to be sure of everything. You take a bit of a gamble, but you take the decision at the very least moment with the information that you have. Those are usually some good ideas.
I decided to have another heuristic for that, but I need your help. We have four libraries. We have logging libraries, analytics library, design system, and data layer. Which one shouldn’t be an external library? Any idea? Data layer. Exactly. Why that? Because if you think about the rate of change, logging, I implement a high rate of change at the beginning and then it fades out. Analytics, similar. Design system is changing but not that often. Data layer instead might change very often, especially when you are migrating or evolving your system. It’s domain specific. Therefore, that shouldn’t be an external library. I’ve seen that as well. Last but not least, ownership. In 2025, you won’t believe that.
Unfortunately, I’ve seen also this. What I expect from a micro-frontends team is that they understand how to code it, testing, deploying, and monitoring. That’s the part that usually is missing. No one is looking into that, but instead is key because it’s a distributed system: you build it, you own it, you run it. Adhere to guardrails. We are asking the developers way more than before. The reality is, it doesn’t exist for me. A team that writes the code, frontend or backend, and throws it on the other side of the fence, doing just testing, and then forgets about the deployment and observability. You need to understand if it fails in production, what fails.
If you think that you have multiple micro-frontends in the same view, and the first line support is saying, we have an error at 3 a.m. in the morning, which team should they call, if they don’t know which is the team that is responsible for something? You need to understand what’s going on. You need to have visibility and improve your logging and visibility inside your micro-frontends through instrumentation. Things like LogRocket, or Sentry, or stuff like that, are your best friends. Therefore, what I recommend is, think, whatever approach you have, not doing in CI/CD, but shift left as close as possible to where the developers have fast iteration, therefore on the process of pulling and pushing code.
Don’t Underestimate Coding Challenges
That’s not all, obviously. We have seen a part of the micro-frontends ideal platform, I don’t underestimate the other things, but the things that I shared with you are the most common mistakes that I’ve seen worldwide. Obviously, server-side rendering, there is still work to do. Nowadays, with modern architecture and modern frameworks like Next.js, or Astro, or QUIC, we start to see some very interesting and compelling ways to build micro-frontends in different ways. I believe that will be a very interesting feature.
Also, we need to be aware of how we need to design our micro-frontends. How can we identify micro-frontends? Because if we start to treat micro-frontends components on the server-side, it’s going to be very nasty. Observability is a key aspect. End-to-end testing also. People are asking me if with micro-frontends something changes on testing. Usually, unit tests and integration tests are the same, but end-to-end testing can change. That’s very important to think about. Security is another part, even management and performance.
Summary
You have seen what micro-frontends are. The team’s ownership, so who is responsible for what in the platform part and then on the value-stream side. The importance of fast feedback loops, because in every system it’s extremely important, and having a decentralized mindset for implementing micro-frontends. Those aspects are usually the issues that you encounter when you start the journey with micro-frontends. Even mature teams are failing on implementing this solution.
See more presentations with transcripts
