MicrofrontendsSeptember 11, 2026 · 9 min

Deploying microfrontends on AWS with Module Federation, S3 and CloudFront

Splitting a frontend into microfrontends is only half the work — the other half is deploying them so each team ships independently without breaking the whole. Here's a concrete AWS setup: each microfrontend built and hosted on its own S3 origin, served through CloudFront, composed at runtime with Module Federation.

The deployment goal: independent, atomic, cache-safe

Each microfrontend must deploy on its own pipeline, its release must be atomic (users never load a half-updated app), and caching must let the shell pick up new remotes without serving a stale entry file. The AWS building blocks map cleanly: S3 for the static artifacts, CloudFront for the CDN and cache control.

One S3 origin per microfrontend

Each microfrontend builds to its own S3 bucket/prefix and exposes a Module Federation remoteEntry.js. The shell (or host app) references those remotes. Because each has its own origin and pipeline, the billing team's deploy touches only the billing artifacts — the dashboard team is unaffected.

// CloudFront cache strategy: fingerprint chunks, don't cache the entry
// remoteEntry.js  -> Cache-Control: no-cache  (always revalidate)
// [name].[hash].js -> Cache-Control: max-age=31536000, immutable
// The entry is small and must be fresh; hashed chunks are forever-cacheable.

The cache subtlety that breaks people

If you cache remoteEntry.js aggressively, a deploy ships new chunks but users keep loading the old entry that points at chunks that may no longer exist — white screen. The fix: the entry file is always revalidated (no-cache), while the content-hashed chunks it references are immutable and cached forever. New deploy, fresh entry, correct chunks, no stale references.

The classic microfrontend production bug is a stale remoteEntry pointing at deleted chunks. Keep the entry revalidated and the hashed chunks immutable, and it can't happen.

Pipeline and resiliency

  • Each microfrontend has its own CI/CD (build -> upload to S3 -> invalidate the entry in CloudFront).
  • Share singletons (React, router, design system) so remotes don't each ship their own copy.
  • Plan the failure case: if a remote fails to load, the shell should render a graceful fallback, not crash the whole page.
  • Monitor per-microfrontend (Sentry/CloudWatch) so an error is attributed to the team that owns it.

Key takeaways

  • Give each microfrontend its own S3 origin and CI/CD pipeline for independent, atomic deploys.
  • Serve through CloudFront; revalidate remoteEntry.js and cache hashed chunks immutably.
  • Share React/router/design-system as singletons across remotes.
  • Render a fallback when a remote fails — one microfrontend down shouldn't take the page down.

FAQ

How do I deploy microfrontends independently on AWS?

Give each microfrontend its own S3 bucket/prefix and CI/CD pipeline, expose a Module Federation remoteEntry.js, and serve everything through CloudFront. Each team's deploy uploads only its own artifacts and invalidates only its entry, so releases are independent and atomic.

Why do microfrontends sometimes show a white screen after deploy?

Usually a stale remoteEntry.js cached by the CDN, still pointing at chunk files a new deploy removed. Fix the cache policy: keep remoteEntry.js revalidated (no-cache) and make content-hashed chunks immutable/forever-cached, so the entry is always fresh and its chunk references always valid.

AA
Ali Asghar

Senior software engineer & technical lead — 6+ years shipping production multi-tenant SaaS, payments and AI integration in Next.js, Node & TypeScript.

Keep reading
When (and how) to transition from a React monolith to microfrontends →The Next.js technical SEO checklist for SaaS that actually ranks →Domain-based multi-tenancy: one repo, four markets, zero hardcoded country logic →