DEV Community

Cover image for Micro Frontends: Enabling Scalable and Autonomous Development with Build-Time Integration
Eden Ella
Eden Ella

Posted on

Micro Frontends: Enabling Scalable and Autonomous Development with Build-Time Integration

Micro frontends (MFEs) are often integrated at runtime rather than build time. This choice isn’t necessarily because runtime integration offers a better user experience—it’s because it enables faster builds and smoother collaboration between teams. With runtime integration, teams can work autonomously, developing, building, and deploying their MFEs independently, often in separate repositories.

However, runtime integration comes with trade-offs. It can lead to inconsistencies in UX, integration challenges, and suboptimal performance. In contrast, build-time integration allows for thorough end-to-end testing, reducing the likelihood of bugs in production. It simplifies dependency management, ensures a consistent UX across the application, and reduces overall bundle(s) size.

The solution presented in this blog implements build-time integration for micro frontends (MFEs) while maintaining team autonomy and ensuring consistency. The key elements of this approach include:

  • Inversion of Control: MFEs integrate into the app shell based on their own implementation rather than being dictated by the app shell team. MFEs implement an interface that "expects" to be injected with an app instance. The app, injected by the application shell, exposes integration slots, global states, and shared functions.

  • Shared Interfaces: The TypeScript interfaces that MFEs need to implement are shared as Bit components, ensuring compatibility and seamless integration.

  • Shared UI Components: The design system, the elementary UI components for the app, are shared as Bit components to maintain a consistent user experience across all MFEs.

  • MFEs as Bit Components: Each MFE is released and shared as a Bit component. MFEs are consumed by the app shell as external dependencies (i.e., as packages).

  • Bit Platform Webhooks: Automatic dependency updates to the application shell when a new MFE is released

Image description

Implementing Build-Time MFE Integration with Bit

Bit can be adopted in different ways. Some teams use Bit as a complete development solution, maintaining their applications as deployable Bit components without traditional Git repositories. However, most Bit users integrate it into existing workflows and tools, and that’s the approach we’ll follow in this example.

Our demo solution is a single-page space travel application built with Vite and React, managed in a Git repository. It integrates two Micro Frontends:

Each MFE is managed in its own Git repository and Bit scope.

Image description

Image description

1. Setting Up Bit Scopes and Git Repositories

The first step is to create Bit scopes and set up Git repositories for the MFEs, their shared UI library, and the orchestration components.

Repository Structure:

  • Foundation: Components responsible for orchestrating and integrating MFEs
  • Design: Shared UI components ensuring a consistent UX
  • Booking: Components for the booking MFE
  • Marketing: Components for the marketing MFE

Note: The app shell in this demo is not a Bit component but a standalone application.

Each Bit scope is hosted on Bit Platform, which provides access control features. In this setup, each scope corresponds to a single repository, but a single repository can also contain multiple Bit scopes if needed.

2. Creating the App Shell and Integration Components

The app shell orchestrates MFEs and provides shared dependencies. It consists of two main parts:

1. A Subscriber Component (Bit)

The subscriber defines how MFEs integrate into the system. It provides an API for MFEs to register routes, header links, and shared states.

export class App {
  private routes: RouteType[] = [];
  private headerLinks: HeaderLink[] = [];

  registerRoutes(routes: RouteType[]) {
    this.routes.push(...routes);
  }

  registerHeaderLinks(headerLinks: HeaderLink[]) {
    this.headerLinks.push(...headerLinks);
  }

  renderApp() {
    return (
      <Theme>
        <Header links={this.headerLinks} />
        <Routes>
          {this.routes.map((route) => (
            <Route key={route.path} path={route.path} element={route.element} />
          ))}
        </Routes>
      </Theme>
    );
  }
}
Enter fullscreen mode Exit fullscreen mode

2. The Application (Non-Bit Component)

The application defines which MFEs should be included and handles the build and deployment process.

import { createRoot } from 'react-dom/client';
import { App, Frontend } from '@cosmo-flux/foundation.subscriber';
import { marketingMfe } from '@cosmo-flux/marketing.marketing-mfe';
import { bookingMfe } from '@cosmo-flux/booking.booking-mfe';

const app = new App();
const frontends: Frontend[] = [marketingMfe, bookingMfe];
frontends.forEach((frontend) => frontend(app));

createRoot(document.getElementById('root')!).render(<>{app.renderApp()}</>);
Enter fullscreen mode Exit fullscreen mode

3. Implementing the MFEs

Each MFE follows the Frontend type defined by the subscriber component. This ensures the MFE teams maintain autonomy while integrating seamlessly.

For example, the Booking MFE registers the Red Planet Reservations page:

import type { Frontend } from '@cosmo-flux/foundation.subscriber';
import { RedPlanetReservations } from '@cosmo-flux/booking.pages.red-planet-reservations';

export const bookingMfe: Frontend = (app) => {
  app.registerRoutes([
    { path: '/reservations', element: <RedPlanetReservations /> },
  ]);
  app.registerHeaderLinks([
    { label: 'Reservations', path: '/reservations' },
  ]);
  return app;
};
Enter fullscreen mode Exit fullscreen mode

Because both the MFE and its components are Bit components, they can be imported directly into the app shell project as regular dependencies.

4. Automating Deployment with Webhooks

To replicate the developer experience of runtime MFEs while leveraging build-time integration, we use Bit Webhooks to automatically trigger the app shell’s CI/CD pipeline when a new stable version of an MFE is released.

Using Bit Webhooks in Composable Software: 5 Use Cases | by Mike Chen | Feb, 2025 | Bits and Pieces

Automate Updates, Streamline Development, and Improve Collaboration with Bit Webhooks

favicon blog.bitsrc.io

Automating the build and deployment process might seem risky at first, but in practice, it enhances stability compared to traditional runtime integrations.

Build-time integration enables comprehensive end-to-end testing and automated verifications, ensuring failures occur during the build process rather than at runtime.

Conclusion

By leveraging Bit for build-time integration, teams can enjoy the best of both worlds—independent development with runtime-like autonomy while maintaining stability, performance, and consistency across the entire application.

Using Bit and Bit Platform, components are shared and synced across separate repositories, allowing you to treat your poly-repo setup as one single virtual monorepo.

Image description

Top comments (0)