Over the past few years, I've supported numerous companies in implementing large enterprise systems using Angular in the frontend. Due to their size and complexity, it's usually necessary to break such systems down into smaller, more manageable pieces. What sounds simple at first glance often proves extremely challenging in practice, because each possible division comes with its own compromises.
Domain-driven design (DDD), particularly its discipline strategic design, have proven extremely helpful in identifying and evaluating suitable approaches. While this approach is now firmly established in the backend, the frontend also benefits enormously from it.
In this article, I'll explore how bounded contexts and context mapping can be transferred to the frontend, why different domain slices may be necessary there, and how we deal with them in event storming, team design, as well as the implementation. I'll also show how a strategic design can be translated into frontend code and what to keep in mind.
What Do We Want to Achieve?
Before we turn to specific DDD principles, it's worth taking a look at the general goals of slicing large systems. Essentially, it's about creating a structure that remains maintainable, understandable, and adaptable – even with increasing complexity. Dividing a system into vertical business-oriented sections has proven to be an effective approach – these sections reflect business functionality instead of technical structures such as components or services..
I use the term vertical broadly, in contrast to horizontal layering that separates concerns by technical function.
Typical goals of such verticals are:
- Low Coupling: Individual verticals should be able to be developed, tested, and deployed as independently as possible. This reduces technical and organizational dependencies. Changes in one area can be implemented locally without causing unintended side effects in other areas.
- High Cohesion: Functionalities that belong together are addressed and implemented together. Changes to a use case occur within a consistent context, without crossing multiple layers or teams. This facilitates understanding, reduces sources of error, and improves changeability.
- Conway's Law: Conway observed that systems reflect the communication structures of their organization. Therefore, those who consciously align the software structure with the team structure (Inverse Conway Maneuver) can avoid friction, clarify responsibilities, and systematically enable autonomy – instead of developing against the organization. In concrete terms, this means that ideally, each team is responsible for one vertical (or even several verticals). Conversely, a vertical should only be managed by one team.
- Enabling autonomous teams: A well-defined vertical allows one team to be fully responsible for a part of the system — both functionally and technically. This creates independent delivery units with clear ownership and faster feedback.
- Reduce cognitive load: Those working on a cohesive vertical only have to deal with a clearly defined functional and technical aspect. This increases focus, productivity, and quality – especially in complex systems.
These principles apply regardless of the chosen approach. However, as we will see shortly, DDD helps enormously in identifying potential verticals that meet these criteria.
Strategic Design
DDD focuses on domain expertise and direct collaboration with domain experts. Strategic Design, one of the two original disciplines of DDD, provides, among other things, concepts and tools for designing complex systems along domain-specific boundaries. In this section, I provide an overview of the advantages of strategic design and then focus on the division into subdomains and bounded contexts.
Subdomains
Strategic Design divides the analyzed business into sub-domains in order to make complexity manageable and to concentrate investments where they create the greatest competitive advantage. Such a subdomain is a business area – for example, an airline could divide its business into subdomains such as booking, check-in, luggage or boarding:
In large software systems, not everything is equally important. Some features give us a decisive edge, others are merely necessary accessories. Strategic design makes these priorities visible by assigning each subdomain to one of three categories:
- Core Domain: Provides the decisive competitive advantage. This is where the most effort is invested.
- Supporting Subdomain: Supports the core domain without being a differentiating factor itself.
- Generic Subdomain: Handles tasks that can be covered by standard solutions and can be purchased separately. Examples include authentication, newsletter distribution, or helpdesk ticketing.
From Subdomains to Bounded Contexts
While subdomains reflect the relevant areas in the "real world," bounded contexts define how these areas are to be represented in the software. Therefore, subdomains are also referred to as the problem space, and bounded contexts as the solution space. Or as Vladik Khononov succinctly puts it in his book Learning Domain-Driven Design , published by O'Reilly:
“Sub-domains are discovered; bounded contexts are designed.”
Each Bounded Context therefore has its own domain model and its own Ubiquitous Language. The domain model ultimately also represents the implementation in code. The Ubiquitous Language consists of terms that must be used consistently within the Bounded Context: in discussions, in documents, and in code.
This makes a bounded context a linguistic boundary ensuring clear terminology, preventing conflicting rules, and allowing teams to develop their model independently. A quick look at the word "flight" shows why this is necessary: In the booking context, it's a sellable offer with attributes such as fare class, price, and seat availability; in the boarding context, it's an operational process with gate, seat, and security status:
If both meanings were to coincide in one model, irrelevant fields and error-prone validations would arise.
The reconciliation between such contexts is often done via domain events in the backend. Booking, for example, publishes a TicketCancelled event. Boarding receives the event and removes the passenger from the list.
Bounded contexts are excellent candidates for verticals. They are the first choice, especially in the core domain. In supporting subdomains, they also offer a suitable basis for slicing, although for pragmatic reasons, you don't always have to adhere strictly to them. With purchased solutions for generic subdomains, you can generally only influence the slicing to a very limited extent.
However, as we will see below, there are other criteria for slicing besides the preferred Bounded Context.
Relationship Between Bounded Contexts and Subdomains
Ideally, each subdomain is mapped as a separate Bounded Context. This leads to a direct mapping in the created system. However, for technical or organizational reasons, it may also be useful to break a subdomain down into multiple Bounded Contexts. This is the case, for example, if the subdomain is too large or complex for a Bounded Context, or if it contains different subdomains with their own languages.
However, purchased standard solutions such as ERP systems or "historically evolved" applications that were not developed with the DDD mindset often cover various subdomains. Thus, there is no clearly defined vocabulary, and the terminology becomes blurred. This, in turn, leads to high coupling and low cohesion—exactly the opposite of what we want to achieve. The anti-corruption layer discussed below helps minimize the influence of such systems on our contexts.
Context Mapping
Context mapping makes the relationships between bounded contexts visible. This helps teams understand who needs whom to be successful and realistically plan the effort for changes and integration. Strategic Design describes some patterns for implementing these relationships. The following example illustrates two of these patterns:
The Booking context requires data from Accounting. Let's assume that Accounting is a purchased standard product without a clear ubiquitous language. To prevent the Booking model from becoming diluted, an Anti-Corruption Layer translates selected parts of the Accounting model into the Booking model. The ACL also allows Booking to address breaking opportunities in Accounting in a central location.
For the other subdomains, Booking offers an Open/Host Service. This publishes selected information (ideally via eventing) and shields details of the Booking model from other contexts. Changes to the Booking model can thus be isolated within the context.
Another pattern in this category is the Shared Kernel. It is a model fragment shared by two or more Bounded Contexts. The advantage is that duplication of work and mapping overhead are eliminated because all teams access the same implementation. The disadvantage is that every change requires coordination and couples the release rhythms of the participating teams – in the event of conflicts, the shared kernel quickly becomes a brake.
Because of these disadvantages, the use of shared kernels is discouraged whenever possible. If necessary, they should be as small as possible. Vlad Khononov emphasizes in his work on DDD that the shared kernel undermines the idea of the bounded context and therefore demands a sound justification for its use. He mentions cases where the same team is responsible for multiple bounded contexts or where the shared kernel represents an intermediate step in the refactoring of an existing system that does not incorporate the ideas of DDD.
Sharing is contrasted with the Separate Ways pattern, where two contexts deliberately implement similar aspects independently. This reduces coordination effort and makes sense if the implementations are already drifting apart over time.
There are several further patterns in this space that are beyond the scope of this article. A complete overview can be found in this still current and well-written article on InfoQ as well as in the repository of the DDD crew, which also offers a well-organized cheat sheet.
Sharing Technical Code is Beyond the Focus of DDD!
When speaking about the Shared Kernel, it should also be mentioned that Context Mapping patterns are about domain-specific code. Sharing technical code, such as design systems, is, on the one hand, outside of DDD's focus and, on the other hand, less critical, since we're generally dealing with more stable APIs.
Whether and how much to share is generally an architectural decision balancing different issues, such as coupling vs. duplicates and consistency. Therefore, such decisions must be made consciously for each specific case, weighing the costs and benefits.
For this reason, the following use of monorepos does not contradict DDD—especially since modern tooling allows us to define which parts of the system may access others. This makes it possible to express deliberate decisions about sharing domain-specific code (in accordance with DDD principles) and technical code (based on further architectural considerations).
How Do You Find Good Context Boundaries?
Now that we've clarified the fundamentals of Strategic Design necessary for domain slicing and also know that Bounded Contexts are excellent candidates for verticals, the question arises as to how to identify them. The good news: DDD offers several heuristics for precisely this question that can indicate separate Bounded Contexts:
- Terms with the same name but different meanings: If a term like passenger, booking, or flight is interpreted differently in different parts of the domain, this is a strong indication of separate contexts. Different ubiquitous languages are colliding here.
- Different models for the same concepts: The same concept must be modeled significantly differently in different areas (e.g. different attributes).
- Different responsibilities: Different responsibilities often lead to different terms and models.
- Pivotal Events : In his book on EventStorming, Alberto Brandolini suggests looking for key moments in a process. He refers to these as pivotal events, which represent a decisive turning point. Such turning points often represent the boundaries of bounded contexts.
Looking at the vocabulary, semantics, and responsibilities is the more traditional way of identifying bounded contexts. Interestingly, pivotal events also align with these concepts but bring several additional useful views into play. The next section looks at them in more depth.
More on Pivotal Events
A typical characteristic of pivotal events is that they involve a change in perspective. This change in perspective can lead to different rules or a different vocabulary. It can also involve a significant change in state or responsibility, and can result in a temporal decoupling.
When booking flights, all of these criteria apply: The flight is suddenly booked (state change), and responsibility is transferred to the airline. The airline now has a new perspective on the flight. For example, the different pricing options are no longer relevant for the subsequent check-in and boarding, and certain rules now apply in the case of a cancellation. For the passenger, the journey continues a few weeks later upon arrival at the airport (temporal decoupling).
A vivid metaphor that makes the idea of pivotal events more tangible is scene changes in a film: An important part of the plot has now been completed, and subsequent scenes will (very likely) build on it. Responsibility can be transferred to other actors, and the new scene can continue the narrative at a different point in time.
The well-known German DDD expert Michael Plöd has investigated further heuristics for identifying pivotal events. He has summed up these findings in his article Finding the Turning Points.
It's important to see the points outlined here for recognizing bounded contexts for what they are: heuristics. As the next section shows, it's quite possible that different heuristics contradict each other. This isn't a bad thing and also shows that there is often no single perfect solution.
Heuristics That Contradict Each Other
The following figure illustrates some of the heuristics discussed previously:
Here we see different responsibilities, pivotal events (squares with arrows) and the key terms as icons.
Now let's try to identify different bounded contexts by applying the discussed heuristics:
- Terminology: Luggage in Check-in Luggage and Pickup Luggage mean the same thing. Luggage might also appear in Booking, but with a different meaning: Here, it refers to purchasing the option to check in a specific number of pieces of luggage.
- Pivotal Events: During the events shown, an important shift in perspective occurs (passenger is now checked in, passenger is now boarded). This also brings new rules, for example, luggage must be unloaded if a checked-in passenger does not show up for boarding.
- Responsibilities: The airline agents are responsible for the entire process from check-in to boarding. Therefore, there could be a unified view of things here.
Funnily, depending on the heuristic we go with, the bounded context containing Check-in Luggage has different boundaries. To be honest, this example was deliberately chosen so that the three heuristics contradict each other. With this, I want to emphasize that one shouldn't let this unsettle one. In such cases, it's important to make a deliberate decision. The originally stated goals naturally play a role. It's also about evaluating different consequences.
This is particularly common in the area of software architecture: there is usually no single perfect solution; rather, there are several options with consequences.
However, I have some good news: These decisions are typically not made alone, but rather are considered in conjunction with the perspectives and experiences of various experts. This also corresponds to the role of a modern architect, who sees himself not as a decision-maker, but as someone responsible for ensuring that conscious decisions are made after weighing options.
An initial decision isn't set in stone. You gain initial experience with it and may decide to refactor later.
Event Storming, described in the next section, is now an extremely popular workshop format that allows the knowledge, perspectives and experiences of different experts to be brought together.
Before we turn to Event Storming, however, I would like to emphasize that the approach discussed here shifts the focus away from a purely technical or data-based (static) perspective and toward the actual processes and interactions within the domain. Because those who only look at the static data – concepts and attributes – easily overlook the fact that the same information can have different meanings and requirements in different contexts. A look at the process, on the other hand, reveals dynamics, role changes, and shifts in purpose – and thus those transitions where the separation into Bounded Contexts makes the most sense.
More on this: Angular Architecture Workshop (Remote, Interactive, Advanced)
Become an expert for enterprise-scale and maintainable Angular applications with our Angular Architecture workshop!
English Version | German Version
Event Storming
Collaboration with domain experts and the consistent development of deep domain knowledge are essential principles of DDD. Only those who truly understand the business can design sustainable systems and identify solutions that remain robust over the long term.
Event Storming, developed by Alberto Brandolini, is a popular interactive workshop format in the DDD environment. It brings together all participants — from domain experts to developers to UX designers — and allows them to combine their knowledge. Using colored sticky notes, the domain is visualized step by step and outlined chronologically.
The focus is on domain events, represented by orange sticky notes. Each domain event describes the completion of a subsection — something that is finished and impacts the subsequent process (e.g., flight booked or passenger checked in). Different perspectives can be discussed immediately on the spot. By placing these events together, a visual model is quickly created that is understandable for everyone.
In the course of a so-called Big Picture Event Storming, the overall view is worked out. It is therefore also ideal for discussing context boundaries. The example used here could be presented as follows in the course of such a workshop:
For better readability, I created this example on a computer. In practice, however, working together on-site is recommended, especially since it promotes communication.
Parts that are not relevant here are simply skipped using ellipses: further events that the participants discovered and further process steps during the flight.
The following information can be obtained from this illustration:
- Events: Orange Slip
- Pivotal Events: Orange notes with yellow, vertical subdivisions
- Swimlanes: Yellow horizontal subdivisions that show optional or parallel processes.
- Milestones: Blue notes at the top that divide the process into a few sections.
The milestones here are chosen to be coarse-grained for the sake of clarity. Further information that is typically placed alongside the domain events in the Big Picture:
- Actors (personas, users, etc.)
- External systems
- Hotspots (sensitive areas with open questions)
- Opportunities and potential
The individual subprocesses can be further elaborated in a subsequent event storming process. A good overview of the additional details discussed in such formats can be found in the DDD Crew Glossary.
For context definition, Brandolini lists several heuristics that partly overlap with those already mentioned above. These include focusing on different usages of terms (language), pivotal events, and responsibilities (actors, personas, etc.). As is common in the DDD environment, he recommends not only focusing on nouns when considering term usage, but also paying attention to verbs, which often better reveal the respective purpose.
In addition to the heuristics already discussed, he introduces further ones. Interestingly, some of them are based on the experts' behavior during collaborative modeling:
- Pay attention to the swimlanes: If separate lanes for independent processes emerge in the EventStorming timeline, this indicates independent Bounded Contexts.
- Pay attention to the people in the room: Domain experts instinctively gather in the areas of their domain, correct notes, etc. Where people cluster or intervene frequently, there is usually a model boundary.
- Pay attention to body language: Head shaking, eye rolling, or other nonverbal signals indicate hidden conflicts or hierarchy friction. Divergent needs are an indicator of separate models.
Using all the heuristics discussed so far, one could define the following context boundaries in the example used here:
Event Storming for the Angular Frontend?
A key principle of Event Storming is bringing together different perspectives. This also applies to the front-end and UX aspects. Therefore, front-end developers, e.g. using Angular or React, and UX experts should also be involved. This can be achieved in two ways:
- Dedicated Event Stormings from the perspective of UX and/or frontend with focus on the user journey
- Integration of frontend and UX aspects into classic Event Stormings
To integrate UX aspects into traditional event stormings, e.g., at the process level, Brandolini suggests adding (UI) wireframes at the relevant points in the process. The manually sketched or prepared wireframes can be placed in the middle of the modeled process using adhesive tape.
To improve UX, Brandolini recommends capturing the mood and feelings of users in event storming in his presentation Transactions Redefined. Someone who has booked the wrong flight, for example, may be unsettled. However, if this person immediately sees that they can cancel the flight free of charge within a certain time frame, this has a positive impact on the user experience.
By explicitly incorporating the front-end perspective, it's easier to determine whether different slices are necessary in the front-end. This has several consequences, which I'll outline in the next section.
Different Slicing in the Frontend
In many projects I have seen, the slicing in the frontend (largely) matches the backend layout:
This leads to verticals that correlate quite well with the goals mentioned at the beginning:
- Low coupling
- High cohesion
- Alignment of teams with the architecture
- Autonomous teams
- Reduced cognitive load
Solid verticals also favor teams that are responsible for creating end-to-end business value in a defined area.
However, I've also seen projects where the team deliberately chose a different slicing approach for the front end. One example was a highly regulated area with complex calculations that frequently had to be adapted to new laws. In the Angular frontend however, the individual processes were relatively simple.
In such cases, the frontend can be seen as its own bounded context with its own language. As is typical in context mapping, concepts from other contexts must be translated into the language of this context.
Alberto Brandolini also illustrates this fact in his thoughtful blog article Customer Journey as a Bounded Context. He provides a very compelling example: booking tickets for an event. While the front-end view is very straightforward, several domains must interact in the backend: ticketing, seat reservation, purchase, and payment (e.g., via a generic payment subdomain). He emphasizes that the customer often speaks their own language and warns:
"[ ... ] when DDD folks finally [ ... ] master the language complexity [ ... ], they can make the final mistake of exposing this complexity to the customer.
Vaughn Vernon also comments on this case in his renowned book Implementing Domain-Driven Design known for his excellent didactics: If the frontend does indeed have a clearly defined language, it has its own simple bounded context that usually has no business logic. However, he also clearly distinguishes this from the concept of a composite UI, which merely integrates fragments of different domains without resulting in a separate language.
Leaving aside the (for me, at best, secondary) question of whether it is a separate Bounded Context, this consideration clearly shows that the mindset of DDD is also extremely helpful in the frontend: For instance, focusing on language and semantics, workshop formats such as EventStorming and applying the discussed heuristics for identifying good candidates for a vertical subdivision.
However, having different slices in the frontend compared to the backend also has some disadvantages: They go at the expense of the goals outlined above. If a separate team is created for the differently sliced frontend, they have less autonomy and no end-to-end responsibility.
I've seen cases where front-end developers were anchored in teams aligned with the back-end structures and sent to a virtual team dedicated to the respective user journey. While this doesn't solve all challenges, it at least mitigates many. Furthermore, this example clearly demonstrates once again that software architecture is very much about balancing consequences and compromises.
On a technical level, the question arises as to where the translation between languages should take place. A very appealing solution for this is the Backend for Frontend (BFF) pattern:
Such a backend for frontend is physically located in the backend, but logically it belongs to the frontend and (ideally) falls under the responsibility of the frontend team. In addition to the ability to translate between bounded contexts, a BFF offers other advantages, for example, with regard to caching, security, and monitoring. An alternative to this that I have come across is orchestration in the frontend. This loses many of the aforementioned advantages, and the frontend becomes more complex at this point. However, the effort required to maintain and operate a dedicated BFF is also eliminated.
Although the general recommendation in such situations is to use a BFF, the decision must be made in the context of the specific project. One more time, it's all about consequences and compromises.
With this discussion, we are already in the middle of the topic of the next section, which revolves around the technical implementation of a strategic design in the frontend.
Implementing Strategic Design with Angular
Architectural work doesn't take place in a vacuum; sooner or later (in my opinion, better sooner than later) it must be broken down to the code level. This also applies to our strategic design. Even if the details of this concrete implementation lie beyond the focus of DDD, it makes a lot of sense that the decisions made — including context boundaries and deliberate decisions regarding communication between contexts — be reflected as explicitly as possible in the code: Everyone should know which context they are in, what to expect from other contexts, and where the boundaries lie.
In my experience, the following options are available for displaying Bounded Contexts in Angular and the frontend in general:
- Folder as context
- Library as context
- Application as context
The first two options lead to a monolithic application, also called a monolith; the third results in a micro frontend architecture.
In general, I recommend a solution that's only as complex as necessary and as simple as possible. We don't want to solve problems we don't have. If using plain folders is good enough for your purpose, consider yourselves lucky!
Context Boundaries for Monoliths
With monoliths, compliance with context boundaries must be monitored, as it's far too easy to override them by importing from other verticals. The solutions Nx and Sheriff, for example, can be used to enforce compliance with Bounded Contexts via linting. Nx does this at the library level in a monorepo; Sheriff, on the other hand, works at the folder level.
Such solutions can be used with several frontend frameworks. Nx, for instance, comes with out-of-the-box support for Angular and React, and Sheriff works with everything that is baed on TypeScript.
Nx but also Sheriff allow to tag individual areas, i.e. libraries or folders, in the solutions. These can reflect the selected Bounded Contexts but also sections such as modules or layers within the Bounded Contexts. Based on these tags, restrictions can then be defined, such as
- Booking may only access Booking and Shared
- Boarding may only access Boarding and Shared
The consequence of this is that Booking is not allowed to access Boarding and vice verse. Usually, there are further restrictions in place because we don't want to grant all parts of Booking access to all parts of shared.
While Shared may contain shared kernels in the sense of DDD (they can also be placed elsewhere), it's important to note that, as discussed above, this pattern should be used with caution and alternatives should be considered.
Rather, a shared area typically contains technical code. Obviously, it's important to prevent it from becoming an all-knowing garbage dump. Therefore, this area will be heavily subdivided or split up to additional modules. Also, careful consideration will be given to which aspects will be exposed via the public API. All of these considerations lie beyond DDD, but nevertheless, they need to be respected when breaking the strategic design down into code.
If you attempt to import something from a non-shared area, e.g., from another domain, you will be warned by the linter. The following figure shows a case where someone tried to access the check-in context from the ticketing context:
To get quick feedback, this check runs directly in the IDE. It's also a good idea to run these linting rules during the build process and reject code that doesn't comply with the specified rules.
The context mapping patterns discussed above can also be implemented on this basis:
- Open/Host Service: The linting rules specify that one domain can only access well-defined functionality, an "API", of another domain. This can be a service in Angular or a barrel.
- Anti-Corruption Layer: The rules allow only the ACL of one domain to access certain other domains.
I blogged about using Sheriff here, and my blog post on Nx can be found here. The Nx team also recently published an article that covers the same topic.
These rules allow the deliberate decisions made during strategic design (as well as others arising from technical considerations) to be explicitly reflected in the code, e.g. in the Angular frontend. This enforces the desired modularization, so such monoliths are often referred to as "Moduliths" (modular monoliths).
The artificial term Modulith is also used to distinguish this architecture from Micro Frontends discussed in the next section.
Micro Frontends
Micro Frontend Architectures provide for (more or less) independent frontends, e.g. Angular or React applicatioins, that are developed and deployed separately by individual teams. These frontends are decoupled from each other. It is essentially a shared-nothing architecture, although some details might be shared for pragmatic reasons.
Micro Frontends make it possible to achieve the criteria initially mentioned — low coupling, high cohesion, autonomous teams, and compliance with Conway's Law — very well. The identified bounded contexts are also generally good candidates for Micro Frontends (as well as for Micro Services in the backend). Therefore, DDD has received a clear boost with the emergence of these architectures.
To present the individual Micro Frontends to the user as a single unit, they must be integrated at runtime. This can be accomplished most easily via hyperlinks. For a more fine-grained integration, it is common to load the Micro Frontends into a shell application:
However, Micro Frontends pose a number of challenges, especially when using single-page applications that are loaded into the browser. These include:
- Larger bundles: Each micro frontend is built separately and must be loaded into a shell sooner or later.
- Conflicts: Micro Frontends can be based on different technologies and versions, which can conflict with each other.
- Styling: Team autonomy works against uniform styling.
Perhaps the most important limitation, however, is that current SPA frameworks weren't designed with the idea of Micro Frontends in mind. Angular's compilation mode, for example, requires all code to be compiled and optimized together to create the smallest possible bundles.
The good news: All of these challenges can be solved. We've helped numerous companies, including well-known banks, insurance companies, automotive, and industrial corporations, with this in recent years. However, this usually requires a small, dedicated platform team to provide solutions in the form of guides or help libraries.
Therefore, you should carefully consider whether this approach is worthwhile. We generally recommend this approach when multiple different teams are delivering parts of a larger whole and collaboration via a monorepo is not possible for technical or organizational reasons. The underlying concepts are also helpful in establishing plugin systems, e.g. for SaaS solutions that need to be adapted for different tenants.
In this blog post, which I wrote together with the Angular team, I explored the mentioned aspects in more detail and provided an overview of Native Federation -- a technology that allows Micro Frontends to be integrated into a shell.
In this article series I go into more detail about the technical details and also show how different frameworks and versions can be combined.
Micro Frontends that reflect Bounded Contexts are usually a good solution for achieving low coupling: The applications are isolated from each other. To share functionality, e.g., via an open/host service, communication between the Micro Frontends can be established using various mechanisms. Here are a few options:
- A simple service bus in the browser
- Simple objects in the global namespace
- Sharing contracts and tokens via npm packages and/or dependency injection
Native Federation also allows for sharing code between individual Micro Frontends.
Summary
Large front-end systems benefit greatly from a composition driven by business concerns. Instead of structuring the system along technical layers, the goal is to create functional units with high coherence, low coupling, and clear accountability. Concepts from DDD and especially Strategic Design — such as subdomains, Bounded Contexts, and context mapping — help to systematically identify and balance candidates for these intersections.
Event Storming is particularly valuable: a collaborative workshop format that visualizes business processes and uncovers contextual boundaries – also with regard to UX and the frontend. This makes it clear whether the frontend requires its own slicing or can be aligned with the backend logic. The decisions made can be enforced with tools like Nx or Sheriff. Micro Frontends on the other side allow for technical decoupling, which increases team autonomy. his results in a frontend architecture that is both domain-driven and maintainable in the long term.