DEV Community

Cover image for Micro Frontend: Common Misconceptions with Case Studies
Juun Roh
Juun Roh

Posted on

Micro Frontend: Common Misconceptions with Case Studies

https://micro-frontends.org

MFE - Micro Frontend?

Original Korean article

Cloud Native and microservices have gained significant attention, leading to the emergence of similar architectural patterns in the frontend space. Micro Frontend (MFE) is at the forefront of this movement, and we're increasingly seeing attempts to adopt this architecture. What exactly is MFE, and in which situations is it suitable?

Definition

A micro frontend is an architectural pattern for web development, where independently developed frontends are composed into a greater whole. - wikipedia

MFE is a frontend architecture that enables independently developed applications to be accessed through a single domain. This structure allows frontend teams responsible for each service to establish autonomous development environments, enabling development without going through complex dependency sharing systems. This also provides the additional benefit of connecting services based on different frameworks.

MFE Promise

he benefits of adopting MFE can be summarized as follows:

  • Independent Deployment: Services are separated and have independent workflows, allowing development and deployment processes that are not constrained by other services.
  • Framework Flexibility: Dependencies can also be separated, allowing each team to configure their application frameworks independently and manage their technology stacks autonomously.
  • Team Autonomy: Through independent development and deployment processes and technology stack separation, teams responsible for each service can manage their services with autonomy.
  • Scaling Development Teams: The size of separated teams can be adjusted according to needs.

However, these are merely side effects of MFE's fundamental adoption purpose.

Betrayal of MFE

Considering the mentioned advantages, there seems to be no reason not to adopt MFE. It appears to be a perfect technical alternative that can solve the main problems in current application ecosystems, such as dependency issues and the need for full application redeployment for bug fixes or minor service updates. However, MFE adoption reverses even the technical advantages that were previously secured beyond these benefits.

Critical Misconceptions

  • NOT Frontend Only: he most commonly overlooked aspect is that MFE doesn't simply mean separating frontend applications. Regardless of the method chosen, MFE results in separated application contexts. Therefore, services for managing global state must be configured separately, as well as a BFF (Backend For Frontend) that acts as an orchestration layer to coordinate the states of each service. You need to directly implement a Global State Manager suitable for Cloud Native environments.
  • Service Communication: This has the greatest impact on application performance. Backend services in MSA architecture can be separated without significantly affecting communication performance because service requests and responses are in JSON format, and each service contains the instances needed for work. MFE is different. Since frontend work happens on the client side, JavaScript code bundles for browser operation must be sent along with responses. Additionally, since communication occurs over HTTP, speed limits are predetermined regardless of computing resources.
  • NOT for Technical Advantages: The core purpose of MFE lies in solving organizational problems, not technical advantages. However, many teams try to adopt MFE for technical benefits like performance improvement or modularization. In reality, MFE is a reflection of organizational structure according to Conway's Law, and technically performs worse than single applications in almost every aspect. Features like framework mixing or independent deployment are merely side effects of solving organizational problems.

MFE adoption means regressing from SPA(Single Page Application) to MPA(Multi Page Application). This is because it abandons all the benefits that SPA brings, such as shared application context and optimized bundle loading. This represents a technical regression rather than progress. Not only does complexity increase with cross-app communication and coordination, but to maintain performance, all optimization techniques covered in Bundle Optimization must be fully applied to every separated application.

MFE Implementation

How is MFE applied to cause such tremendous complexity increases?

here are two main methods for applying MFE:

  1. Multi-zone (aka route proxy): A method that rewrites shell application route access to remote URLs of other applications
  2. Module Federation: A method that imports each application as modules at runtime through remote entry configuration

Both methods seem simple based on simple explanations. You just rewrite routes to provide service access continuity, or export and import in module form like npm packages. However, the problems are hidden in invisible places.

1. Multi-Zones

This route rewriting method appears simple but actually most accurately reflects the MFE structure. Next.js provides this functionality through the rewrites setting in next.config.js.

Multi-Zones Diagram, Vercel

The multi-zone approach has each application running on independent servers, with the shell application proxying requests to the appropriate application based on specific route patterns. For example, /shop/* paths route to the shopping service, and /admin/* paths route to the admin service.

module.exports = {
  async rewrites() {
    return [
      {
        source: '/shop/:path*',
        destination: 'https://shop-app.example.com/:path*'
      },
      {
        source: '/admin/:path*',
        destination: 'https://admin-app.example.com/:path*'
      }
    ]
  }
}
Enter fullscreen mode Exit fullscreen mode

The core problem with this approach is that the entire application must be reloaded for every page transition. Since each service runs on independent servers, the browser loads completely new pages when routes change, which means abandoning SPA's core advantage of fast navigation. Additionally, this method doesn't allow service separation at the component level. However, complete independence can be secured as each application has separated dependencies and lifecycles.

2. Module Federation

Module Federation emerged to overcome Multi-zone's limitations. It builds each application as modules that can be dynamically loaded at runtime, combining multiple micro frontends within a single shell application.

The key difference from Multi-zone is that it maintains Single Page Application characteristics. Since each micro frontend operates as JavaScript modules, there's no need to reload entire pages during page transitions, and fine-grained separation at the component level is possible.

// Host Application (Shell)
const ModuleFederationPlugin = require('@module-federation/webpack');

module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'shell',
      remotes: {
        shop: 'shop@http://localhost:3001/remoteEntry.js',
        admin: 'admin@http://localhost:3002/remoteEntry.js'
      }
    })
  ]
};

// Remote Application (Shop)
module.exports = {
  plugins: [
    new ModuleFederationPlugin({
      name: 'shop',
      filename: 'remoteEntry.js',
      exposes: {
        './ShopApp': './src/App',
        './ProductList': './src/components/ProductList'
      }
    })
  ]
};
Enter fullscreen mode Exit fullscreen mode

However, this approach also has serious problems:

  • Runtime Dependency Resolution: Dependency conflicts between modules must be resolved at runtime, which can cause unpredictable errors.
  • Bundle Size Explosion: Common dependencies may be loaded duplicately, or bundle sizes can increase dramatically due to the complexity of shared dependency configuration.
  • Type Safety Loss: In TypeScript environments, it's difficult to accurately convey type information from remote modules, significantly degrading type safety.
  • Development Complexity: Multiple applications must run simultaneously, and each build process must be managed, causing exponential increases in development environment complexity.

Additionally, unlike Multi-zones, dependency relationships are created, and some module updates need to be synchronized, preventing complete independence.

Both methods cause JavaScript bundle size increases, and without dedicating considerable time to detailed optimization, service performance will seriously deteriorate.

Based on the characteristics of both approaches, MFE is most suitable for applications with the following characteristics:

  • When main dependencies required for service provision are clearly distinguished
  • When connectivity between services can be minimized (serializable context, acceptable design transitions, etc.)
  • When loading delays of individual services or components don't significantly impact users

Shell Application

What exactly is the Shell Application that appears in both methods above? The Shell Application is a centralized application that acts as an orchestrator in the MFE structure. It's the entry point that users actually access and takes responsibility for integrating and managing each micro frontend.

The main responsibilities of Shell Application include:

  • Routing Orchestration: Routes user requests to appropriate micro frontends and manages overall navigation flow.
  • Global State Management: Centrally manages state that must be shared among multiple micro frontends (user authentication, theme settings, etc.).
  • Error Boundary: Handles errors occurring in individual micro frontends and ensures overall application stability.

The problem is that this Shell Application itself becomes another complex system. Beyond simple routing or module loading, it must substantially perform coordinator roles for distributed systems, giving it considerable complexity. Ultimately, adopting MFE means building and maintaining this orchestration layer in addition to the existing monolithic frontend.

Looking at the responsibilities that Shell Application takes on, we can identify something strange. It takes on backend-like responsibilities that don't match its classification as belonging to Frontend. Many MFE introduction articles mention Shell Application as a Frontend service, but is it really appropriate to classify this as Frontend territory?

Case Studies

Spotify

"It was very slow to iterate upon and experiment, especially when it came to making changes across multiple views like updating the visual style."

Spotify is a case that moved away from MFE. They initially used an iframe-based micro frontend structure but decided to completely rewrite in 2016. The reasons were:

  • Performance Issues: Long loading times due to having to re-download many resources every time switching between views
  • Maintenance Complexity: Maintenance became difficult as multiple teams used different technology stacks
  • Development Friction: It was very slow to apply changes across multiple views (like visual style updates)

After rebuilding as a single application based on React + Redux, they achieved performance that surpassed the previous web player in all key metrics. The Spotify case is a representative example showing that MFE's theoretical advantages can actually be hindrances in real environments.

Interestingly, Spotify's MFE failure was closely related to organizational problems of the same period. You can check the retrospective on "the Spotify Model" here, where autonomous squads using different technology stacks and developing without coordination was the root cause of MFE's maintenance complexity and development friction. According to Conway's Law, software structure reflects organizational structure, and Spotify failed by trying to solve organizational problems with technical architecture.

Facebook: BigPipe

The Facebook BigPipe service improvement case introduced as a Micro Frontend Best Practice in the NIA Korea Intelligence Information Society Agency Issue Report is a typical classification error example.

BigPipe is a server-side rendering optimization technique developed by Facebook in 2009 to reduce web page loading times. It divides web pages into small units called "pagelets", processes them in parallel on the server, then streams them to the client. This essentially corresponds to backend architecture optimization and is completely different from the MFE concept we're currently discussing.

BigPipe's core features:

  • Server-side optimization: Parallel generation of page components on the server
  • Streaming response: Sequential transmission of completed components to the client
  • Progressive rendering: Allows users to see parts of the page first

This actually works as lazy loading components from the user's perspective. Getting components partly, differs in which side they are processed.

Classifying such techniques as MFE is the same type of conceptual confusion as classifying Shell Application as Frontend mentioned earlier. This is another case showing the immaturity of the MFE field, confusing performance optimization techniques with architectural patterns.

Conclusion

As examined in this article, MFE is still a conceptually unestablished immature field. Cases like classifying Shell Application as Frontend or introducing backend optimization techniques like BigPipe as MFE Best Practices show how mixed this field is.

More importantly, the essence of MFE lies in organizational problems, not technical solutions. If considering MFE adoption, you should first approach it from an organizational dimension:

  • Are team collaboration processes clearly established?
  • Are there organizational reasons to abandon technology stack unity?
  • Does a governance system for cross-team coordination exist?
  • Is there organizational capacity to handle the increased complexity of distributed systems?

If you're trying to adopt MFE for technical purposes like performance improvement or development efficiency, it would be wiser to first consider proven techniques like bundle optimization or modularization. MFE should be a last resort for organizational problems and should be a carefully considered architectural choice after fully understanding its complexity and costs.

Top comments (0)