Vercel Logo

Introduction to Remote Components

Throughout this course, you've built vertical microfrontends: splitting by route where each page belongs to one application. Remote components are the horizontal approach: embedding components from different applications on the same page.

Outcome

Understand the difference between vertical and horizontal microfrontends and know when to consider remote components.

Vertical vs Horizontal Recap

Vertical (what you've built):

Page at /docs/api
└── Entirely served by docs app
    ├── Header (shared package)
    ├── Content
    └── Footer (shared package)

Horizontal (remote components):

Page at /
└── Served by marketing app
    ├── Header (REMOTE from header-app)
    ├── Hero (local component)
    ├── Features (local component)
    └── Footer (REMOTE from footer-app)

With horizontal microfrontends, components from different applications render on the same page at runtime.

When to Consider Horizontal

Remote components solve specific problems:

ScenarioWhy Remote Components Help
Shared header across portfolioOne header app, embedded everywhere
Different teams own page sectionsTeam A owns header, Team B owns content
Runtime updates without redeployUpdate header without rebuilding all hosts
Embedded widgetsCheckout widget on multiple sites
Section-level migration from legacyModernize page sections incrementally without rewriting the whole route

How Remote Components Work

Remote Components build on your Microfrontends setup. The remote-components package adds the runtime helpers; @vercel/microfrontends handles the routing through microfrontends.json. Install both in the host and in the app exposing the component:

pnpm add @vercel/microfrontends remote-components

The exposing app wraps the page in ExposeRemoteComponent:

components-app/app/components/header/page.tsx
import { ExposeRemoteComponent } from "remote-components/remote/nextjs/app";
 
export default function Page() {
  return (
    <ExposeRemoteComponent>
      <h2>Hello from the header!</h2>
    </ExposeRemoteComponent>
  );
}

The host app consumes it with ConsumeRemoteComponent. By default this is a Server Component, so the remote content is SSR'd:

host-app/app/page.tsx
import { ConsumeRemoteComponent } from "remote-components/host/nextjs/app";
 
export default function Page() {
  return (
    <div>
      <ConsumeRemoteComponent src="/components/header" />
      <main>Page content</main>
      <ConsumeRemoteComponent src="/components/footer" />
    </div>
  );
}

The path /components/header resolves through the Microfrontends proxy to whichever app exposes that route. The remote component:

  1. Fetches from the exposing application (components-app)
  2. Renders the component as if it were local
  3. No iframes - It's embedded directly in the DOM
  4. SSR by default - Server-renders like native Server Components

Configuration

Both the host and the exposing app wrap their next.config with withRemoteComponentsConfig and withMicrofrontends:

next.config.ts
import { withRemoteComponentsConfig } from "remote-components/config/nextjs";
import { withMicrofrontends } from "@vercel/microfrontends/next/config";
 
export default withRemoteComponentsConfig(
  withMicrofrontends({
    // your Next.js config
  }),
);

Routing is declared in microfrontends.json the same way you've done throughout the course. The exposing app gets a path like /components/:path*, and the host resolves remote src values against it.

State Sharing

The most common question: "How do I share state between host and remote?"

To pass shared modules like next/image, next/link, next/navigation, or client-side configuration to remote components, add RemoteComponentsClientProvider to the host's layout:

app/providers.tsx
"use client";
 
import { RemoteComponentsClientProvider } from "remote-components/host/nextjs/app/client-only";
 
export function Providers({ children }: { children: React.ReactNode }) {
  return (
    <RemoteComponentsClientProvider>
      {children}
    </RemoteComponentsClientProvider>
  );
}

The provider lives in a Client Component, but ConsumeRemoteComponent continues to render on the server. With this in place, both host and remote can share React context across the boundary, so a theme toggle in the host updates the remote header.

Vertical-First Philosophy

For most teams, the recommendation is:

  1. Start with vertical microfrontends (this course)
  2. Use shared packages for common components
  3. Consider horizontal only when shared packages aren't enough

Horizontal adds complexity:

  • Module sharing configuration
  • Cache invalidation when remotes update
  • More moving parts to debug

Vertical is simpler and solves most use cases.

When Vertical Isn't Enough

Consider remote components when:

  • Same component, many hosts - A header used by 10+ separate applications (not in a monorepo)
  • Independent deployment of components - Marketing wants to update the header without docs redeploying
  • Different teams, same page - Team A owns navigation, Team B owns search, Team C owns content

Example: Multi-Site Header

Imagine you have:

  • marketing.example.com
  • docs.example.com
  • app.example.com

All need the same header. With shared packages in a monorepo, you'd need to redeploy all three when the header changes.

With remote components:

  1. header-app deploys
  2. All hosts pick up the new header (via ISR revalidation)
  3. No coordination needed

SSG/ISR with Remotes

Remote components support static generation:

Build time:
Host fetches remote component → Renders → Saves static HTML

Runtime (ISR):
Remote updates → Host revalidates → New HTML includes updated remote

On Vercel with the App Router, invalidation is automatic. Remote Components tag their fetch calls, and Vercel triggers revalidation on the host whenever a remote redeploys, no manual configuration required.

Done-When

  • You understand vertical vs horizontal microfrontends
  • You know when to consider remote components
  • You can identify the remote-components package and its host/remote entry points
  • You understand how state is shared via RemoteComponentsClientProvider

Decision Guide

SituationRecommendation
Monorepo with shared packagesUse shared packages (simpler)
Multiple repos, same headerConsider remote components
Single teamProbably don't need horizontal
3+ teams on same pageRemote components may help
You want runtime updatesRemote components
You want simplicityVertical + shared packages

What's Next

In the final lesson, you'll review the key decisions and get resources for continuing your microfrontends journey.