Microfrontends allow teams to work independently of each other by splitting the application into smaller, shareable, and modular components.
Microfrontends allow teams to work independently of each other by splitting the application into smaller, shareable, and modular components. The primary goal for a microfrontend strategy is to reduce the size of a single application to improve developer velocity while still allowing teams to collaborate with each other.
We recommend reading the "How it works" section to understand the reasoning behind our implementation and the "What's included" section to know more about the tools we used.
https://solutions-microfrontends.vercel.app
You can choose from one of the following two methods to use this repository:
Deploy the example using Vercel:
Execute create-next-app
with pnpm to bootstrap the example:
pnpm create next-app --example https://github.com/vercel/examples/tree/main/solutions/microfrontends microfrontends
Next, run the included Next.js apps in development mode:
pnpm dev
Deploy on Vercel (Documentation).
The example is a monorepo built with Turborepo with the following setup:
acme-design-system
package and its setup is shared in the acme-storybook
packageThere are many strategies for designing microfrontends and your approach will be dictated by how you want to structure your applications and teams. We'll share a few different approaches and how they work.
Multi-Zones is a way of having independent Next.js applications that all render on a common domain. This is a method for building separation of concerns in large teams. It works well if a single domain has separate groupings of pages where a user doesn't navigate between the groups very often.
In this example, ./apps/main is our main app, and ./apps/docs is a separate app that handles all routes for /docs/**
. In the demo, you'll notice that navigating to /docs
keeps you in the same domain. We have multiple apps in the same domain that are built independent of each other.
You'll notice that transitions between /docs/*
and /
have to perform a full page refresh because the separate Next.js apps can't share their JS and don't have common chunks. Next.js prefetching is not possible here, and you have to rely on your own browser prefetching to streamline the transitions (see packages/acme-components/src/prefetch-cross-zone-links.tsx
for an example). The slower transitions between apps may or may not be a problem depending on your specific use case. For that reason, we only recommend using Multi-Zones for cases where you have pages that are logically in separate applications but need to be served on the same domain.
For example, having a home app with your landing, marketing and legal pages and then having another app that handles all the pages related to documentation is a good separation of concerns, your users will only notice a slow transition once they move from your home app to view your documentation. Pro tip: Using target="_blank"
in this situation is a nice improvement!
./packages/acme-design-system features multiple components with CSS Modules and Tailwind. The components are installed in the app as a dependency and the compilation step is handled by SWC.
All the CSS used by the app and components is unified by Tailwind, so having components outside the app doens't increase the CSS bundle size.
HMR and React Fast Refresh work as expected even though the components live outside the app and have a different build process.
This example uses a monorepo to make it easier to share code across separate microfrontends. When a change is made to a component used by multiple applications, the developer only has to change one repository and Vercel will automatically deploy all affected applications. This example uses Turborepo to improve the monorepo experience.
While a monorepo is very useful, the tooling and approaches described above should also work with polyrepos. The most important difference is that, when packages are outside of your application's repository, you won't be able to have hot module reloading for your packages out-of-the-box. In this case, you will install the package in your applications and control updates with versioning. To earn HMR, you would need to link node modules with a package manager. Any time the common code is changed, the package version would need to be bumped and consumers would have to update their dependency and release the application.
Module federation is a strategy for building applications in a large organization with many teams that want to prioritize shipping velocity. We encourage you to research module federation as an option for helping teams build as a part of a large organization where teams may not have the opportunity to communicate and work together.
If sharing code across repositories, Changesets is a great tool to manage versions, create changelogs, and publish to npm. It's preconfigured in this example so you can start publishing packages immediately.
It's worth installing the Changesets bot on your repository to more easily manage contributions.
To generate a changeset, run the following command in the root of the project:
pnpm changeset
The Changeset CLI will ask you a couple of questions:
space
to select the packages you want to include in the changeset
.space
to select the packages you want to bump versions for.changeset
folder with the summary and a list of the packages included.The example ships with a GitHub action named Release to automatically publish changesets to npm after pushing to the main
branch.
You'll need to create an NPM_TOKEN
and GITHUB_TOKEN
and then add them to your GitHub repository settings so that the action can publish to npm.
Publishing can also be done manually with:
pnpm release
The action will run the same release
script defined in package.json
, which looks like this:
turbo run build --filter=main... && changeset publish
Turborepo will run the build
script for all publishable dependencies of the main
app, excluding the main
app itself, and then publishes the new versions to npm.
By default, this example uses acme
as the npm organization. To change this, do the following:
packages/*
to replace acme
with your desired scopeacme
with your desired scopepnpm install
Microfrontends allow teams to work independently of each other by splitting the application into smaller, shareable, and modular components.
Microfrontends allow teams to work independently of each other by splitting the application into smaller, shareable, and modular components. The primary goal for a microfrontend strategy is to reduce the size of a single application to improve developer velocity while still allowing teams to collaborate with each other.
We recommend reading the "How it works" section to understand the reasoning behind our implementation and the "What's included" section to know more about the tools we used.
https://solutions-microfrontends.vercel.app
You can choose from one of the following two methods to use this repository:
Deploy the example using Vercel:
Execute create-next-app
with pnpm to bootstrap the example:
pnpm create next-app --example https://github.com/vercel/examples/tree/main/solutions/microfrontends microfrontends
Next, run the included Next.js apps in development mode:
pnpm dev
Deploy on Vercel (Documentation).
The example is a monorepo built with Turborepo with the following setup:
acme-design-system
package and its setup is shared in the acme-storybook
packageThere are many strategies for designing microfrontends and your approach will be dictated by how you want to structure your applications and teams. We'll share a few different approaches and how they work.
Multi-Zones is a way of having independent Next.js applications that all render on a common domain. This is a method for building separation of concerns in large teams. It works well if a single domain has separate groupings of pages where a user doesn't navigate between the groups very often.
In this example, ./apps/main is our main app, and ./apps/docs is a separate app that handles all routes for /docs/**
. In the demo, you'll notice that navigating to /docs
keeps you in the same domain. We have multiple apps in the same domain that are built independent of each other.
You'll notice that transitions between /docs/*
and /
have to perform a full page refresh because the separate Next.js apps can't share their JS and don't have common chunks. Next.js prefetching is not possible here, and you have to rely on your own browser prefetching to streamline the transitions (see packages/acme-components/src/prefetch-cross-zone-links.tsx
for an example). The slower transitions between apps may or may not be a problem depending on your specific use case. For that reason, we only recommend using Multi-Zones for cases where you have pages that are logically in separate applications but need to be served on the same domain.
For example, having a home app with your landing, marketing and legal pages and then having another app that handles all the pages related to documentation is a good separation of concerns, your users will only notice a slow transition once they move from your home app to view your documentation. Pro tip: Using target="_blank"
in this situation is a nice improvement!
./packages/acme-design-system features multiple components with CSS Modules and Tailwind. The components are installed in the app as a dependency and the compilation step is handled by SWC.
All the CSS used by the app and components is unified by Tailwind, so having components outside the app doens't increase the CSS bundle size.
HMR and React Fast Refresh work as expected even though the components live outside the app and have a different build process.
This example uses a monorepo to make it easier to share code across separate microfrontends. When a change is made to a component used by multiple applications, the developer only has to change one repository and Vercel will automatically deploy all affected applications. This example uses Turborepo to improve the monorepo experience.
While a monorepo is very useful, the tooling and approaches described above should also work with polyrepos. The most important difference is that, when packages are outside of your application's repository, you won't be able to have hot module reloading for your packages out-of-the-box. In this case, you will install the package in your applications and control updates with versioning. To earn HMR, you would need to link node modules with a package manager. Any time the common code is changed, the package version would need to be bumped and consumers would have to update their dependency and release the application.
Module federation is a strategy for building applications in a large organization with many teams that want to prioritize shipping velocity. We encourage you to research module federation as an option for helping teams build as a part of a large organization where teams may not have the opportunity to communicate and work together.
If sharing code across repositories, Changesets is a great tool to manage versions, create changelogs, and publish to npm. It's preconfigured in this example so you can start publishing packages immediately.
It's worth installing the Changesets bot on your repository to more easily manage contributions.
To generate a changeset, run the following command in the root of the project:
pnpm changeset
The Changeset CLI will ask you a couple of questions:
space
to select the packages you want to include in the changeset
.space
to select the packages you want to bump versions for.changeset
folder with the summary and a list of the packages included.The example ships with a GitHub action named Release to automatically publish changesets to npm after pushing to the main
branch.
You'll need to create an NPM_TOKEN
and GITHUB_TOKEN
and then add them to your GitHub repository settings so that the action can publish to npm.
Publishing can also be done manually with:
pnpm release
The action will run the same release
script defined in package.json
, which looks like this:
turbo run build --filter=main... && changeset publish
Turborepo will run the build
script for all publishable dependencies of the main
app, excluding the main
app itself, and then publishes the new versions to npm.
By default, this example uses acme
as the npm organization. To change this, do the following:
packages/*
to replace acme
with your desired scopeacme
with your desired scopepnpm install