Microfrontends
Microfrontends let you split a single application into smaller, independently deployable units that render as one cohesive application. Different teams using different technologies can develop, test, and deploy each microfrontend.
Use microfrontends when you want to:
- Enable many teams to deploy independently without coordinating releases
- Gradually migrate from a monolith to a distributed architecture
- Build multi-framework applications (for example, Astro, Remix, and Next.js in one app)
Create a microfrontend project:
This template automatically creates a router worker with pre-configured routing logic, and lets you configure Service bindings to Workers you have already deployed to your Cloudflare account. The code or this template is available on GitHub at cloudflare/templates ↗.
graph LR
A[Browser Request] --> B[Router Worker]
B -->|Service Binding| C[Microfrontend A]
B -->|Service Binding| D[Microfrontend B]
B -->|Service Binding| E[Microfrontend C]
The router worker:
- Analyzes the incoming request path
- Matches it against configured routes
- Forwards the request to the appropriate microfrontend via service binding
- Rewrites HTML, CSS, and headers to ensure assets load correctly
- Returns the response to the browser
Each microfrontend can be:
- A full-framework application (Next.js, SvelteKit, Astro, etc.)
- A static site with Workers Static Assets
- Built with different frameworks and technologies
The router worker uses a ROUTES environment variable to determine which microfrontend handles each path. Routes are matched by specificity, with longer paths taking precedence.
Example ROUTES configuration:
{ "routes": [ { "path": "/app-a", "binding": "MICROFRONTEND_A", "preload": true }, { "path": "/app-b", "binding": "MICROFRONTEND_B", "preload": true }, { "path": "/", "binding": "MICROFRONTEND_HOME" } ], "smoothTransitions": true}Each route requires:
path: The mount path for the microfrontend (must be distinct from other routes)binding: The name of the service binding in your Wrangler configuration filepreload(optional): Whether to prefetch this microfrontend for faster navigation
When a request comes in for /app-a/dashboard, the router:
- Matches it to the
/app-aroute - Forwards the request to
MICROFRONTEND_A - Strips the
/app-aprefix, so the microfrontend receives/dashboard
The router includes path matching logic that supports:
// Static paths{ "path": "/dashboard" }
// Dynamic parameters{ "path": "/users/:id" }
// Wildcard matching (zero or more segments){ "path": "/docs/:path*" }
// Required segments (one or more segments){ "path": "/api/:path+" }The router worker uses HTMLRewriter to automatically rewrite HTML attributes to include the mount path prefix, ensuring assets load from the correct location.
When a microfrontend mounted at /app-a returns HTML:
<link rel="stylesheet" href="/assets/styles.css" /><script src="/assets/app.js"></script><img src="/static/logo.png" />The router rewrites it to:
<link rel="stylesheet" href="/app-a/assets/styles.css" /><script src="/app-a/assets/app.js"></script><img src="/app-a/static/logo.png" />The rewriter handles these attributes across all HTML elements:
href,src,poster,action,srcsetdata-*attributes likedata-src,data-href,data-background- Framework-specific attributes like
astro-component-url
The router only rewrites paths that start with configured asset prefixes to avoid breaking external URLs:
// Default asset prefixesconst DEFAULT_ASSET_PREFIXES = [ "/assets/", "/static/", "/build/", "/_astro/", "/fonts/",];Most frameworks work with the default prefixes. For frameworks with different build outputs (like Next.js which uses /_next/), you can configure custom prefixes using the ASSET_PREFIXES environment variable:
["/_next/", "/public/"]The router also rewrites CSS files to ensure url() references work correctly. When a microfrontend mounted at /app-a returns CSS:
.hero { background: url(/assets/hero.jpg);}
.icon { background: url("/static/icon.svg");}The router rewrites it to:
.hero { background: url(/app-a/assets/hero.jpg);}
.icon { background: url("/app-a/static/icon.svg");}The router also handles:
- Redirect headers: Rewrites
Locationheaders to include the mount path - Cookie paths: Updates
Set-Cookieheaders to scope cookies to the mount path
When preload: true is set on a static mount route, the router automatically preloads those routes to enable faster navigation. The router uses browser-specific optimization to provide the best performance for each browser:
For Chromium-based browsers, the router uses the Speculation Rules API - a modern, browser-native prefetching mechanism:
- Injects
<script type="speculationrules">into the<head>element - Browser handles prefetching automatically with optimal priority management
- Respects user preferences (battery saver, data saver modes)
- Uses per-document in-memory cache for faster access
- Not blocked by Cache-Control headers
- More efficient than JavaScript-based fetching
Example injected speculation rules:
{ "prefetch": [ { "urls": ["/app1", "/app2", "/dashboard"] } ]}
## Smooth transitions
You can enable smooth page transitions between microfrontends using the [View Transitions API](https://developer.mozilla.org/en-US/docs/Web/API/View_Transitions_API).
To enable smooth transitions, set `"smoothTransitions": true` in your `ROUTES` configuration:
```json{ "routes": [ { "path": "/app-a", "binding": "MICROFRONTEND_A" }, { "path": "/app-b", "binding": "MICROFRONTEND_B" } ], "smoothTransitions": true}The router automatically injects CSS into HTML responses:
@supports (view-transition-name: none) { ::view-transition-old(root), ::view-transition-new(root) { animation-duration: 0.3s; animation-timing-function: ease-in-out; } main { view-transition-name: main-content; } nav { view-transition-name: navigation; }}This feature only works in browsers that support the View Transitions API. Browsers without support will navigate normally without animations.
To add a new microfrontend to your application after initial setup:
-
Create and deploy the new microfrontend worker
Deploy your new microfrontend as a separate Worker. This can be a framework application (Next.js, Astro, etc.) or a static site with Workers Static Assets.
-
Add a service binding in your router's Wrangler configuration file
{"$schema": "./node_modules/wrangler/config-schema.json","services": [{"binding": "MICROFRONTEND_C","service": "my-new-microfrontend"}]}[[services]]binding = "MICROFRONTEND_C"service = "my-new-microfrontend" -
Update the
ROUTESenvironment variableAdd your new route to the
ROUTESconfiguration:{"routes": [{ "path": "/app-a", "binding": "MICROFRONTEND_A", "preload": true },{ "path": "/app-b", "binding": "MICROFRONTEND_B", "preload": true },{ "path": "/app-c", "binding": "MICROFRONTEND_C", "preload": true },{ "path": "/", "binding": "MICROFRONTEND_HOME" }]} -
Redeploy the router worker
Terminal window npx wrangler deploy
Your new microfrontend is now accessible at the configured path (for example, /app-c).
During development, you can test your microfrontend architecture locally using Wrangler's service binding support. Run the router Worker locally using wrangler dev, and then in separate terminals run each of the microfrontends.
If you only need to work on one of the microfrontends, you can run the others remotely using remote bindings, without needing to have access to the source code or run a local dev server.
For each microfrontend you want to run remotely while in local dev, configure its service binding with the remote flag:
{"services": [ { "binding": "<BINDING_NAME>", "service": "<WORKER_NAME>", "remote": true }]}[[services]]binding = "<BINDING_NAME>"service = "<WORKER_NAME>"remote = trueEach microfrontend can be deployed independently without redeploying the router or other microfrontends. This enables teams to:
- Deploy updates on their own schedule
- Roll back individual microfrontends without affecting others
- Test and release features independently
When you deploy a microfrontend worker, the router automatically routes requests to the latest version via the service binding. No router changes are required unless you are adding new routes or updating the ROUTES configuration.
To deploy to production, you can use custom domains for your router worker, and configure Workers Builds for continuous deployment from your Git repository.
Was this helpful?
- Resources
- API
- New to Cloudflare?
- Directory
- Sponsorships
- Open Source
- Support
- Help Center
- System Status
- Compliance
- GDPR
- Company
- cloudflare.com
- Our team
- Careers
- © 2026 Cloudflare, Inc.
- Privacy Policy
- Terms of Use
- Report Security Issues
- Trademark
-