Local Development
The local proxy stitches your apps together so you can test microfrontends routing without deploying.
Outcome
Run all three applications through the microfrontends proxy at localhost:3024 with working cross-app navigation.
The Local Proxy
The @vercel/microfrontends package includes a development proxy that mimics Vercel's production routing locally:
localhost:3024 (proxy)
├── / → localhost:3000 (marketing)
├── /pricing → localhost:3000 (marketing)
├── /docs/* → localhost:3001 (docs)
├── /app/* → localhost:3002 (dashboard)
└── /settings/* → localhost:3002 (dashboard)
When you visit localhost:3024/docs, the proxy routes to the docs app at localhost:3001.
Fast Track
- Add
localProxyPortto microfrontends.json - Run
pnpm devfrom the root - Visit
localhost:3024to see the stitched application
Hands-on Exercise 2.3
Enable and test the local development proxy.
Part 1: Configure the Proxy Port
Update apps/marketing/microfrontends.json:
{
"$schema": "https://openapi.vercel.sh/microfrontends.json",
"applications": {
"acme-marketing": {
"development": {
"fallback": "acme-marketing.vercel.app",
"local": 3000
}
},
"acme-docs": {
"routing": [
{
"paths": ["/docs", "/docs/:path*"]
}
],
"development": {
"local": 3001
}
},
"acme-dashboard": {
"routing": [
{
"paths": ["/app", "/app/:path*", "/settings", "/settings/:path*"]
}
],
"development": {
"local": 3002
}
}
},
"options": {
"localProxyPort": 3024
}
}development.local is the port each app runs on. The default app's development.fallback points to production, so the proxy has somewhere to send requests for any app you aren't running locally. The proxy matches running apps to these keys by package name, which is why the package.json names match the keys.
Part 2: Start All Apps
From the monorepo root:
pnpm devYou should see output like:
• Packages in scope: @acme/ui, acme-dashboard, acme-docs, acme-marketing
• Running dev in 3 packages
acme-marketing:dev: ready - started server on 0.0.0.0:3000
acme-docs:dev: ready - started server on 0.0.0.0:3001
acme-dashboard:dev: ready - started server on 0.0.0.0:3002
The proxy starts automatically when Turborepo detects microfrontends configuration.
Part 3: Test Cross-App Navigation
Open http://localhost:3024 in your browser.
- Marketing homepage loads - You're at
/served by marketing app - Click "Docs" in the header - Navigates to
/docsserved by docs app - Click "Dashboard" in the header - Navigates to
/appserved by dashboard app - Click "Home" in the header - Back to
/served by marketing app
All navigation happens through the same domain (localhost:3024), just like production.
Try It
Verify routing with the browser's network tab:
- Open DevTools → Network
- Visit
localhost:3024/docs - Look at the request - it's to
localhost:3024/docs - The proxy forwards it to
localhost:3001/docs
You can also test that paths reach the correct app:
| URL | Expected App | Expected Page |
|---|---|---|
localhost:3024/ | marketing | Home |
localhost:3024/pricing | marketing | Pricing |
localhost:3024/docs | docs | Docs index |
localhost:3024/docs/api | docs | (404 - page doesn't exist yet) |
localhost:3024/app | dashboard | Dashboard |
localhost:3024/settings | dashboard | Settings |
Debugging Proxy Issues
If something isn't routing correctly, enable debug logging. Set the MFE_DEBUG=1 environment variable, or pass debug: true to withMicrofrontends.
Check Proxy Status
The proxy logs which app it routes to:
[proxy] GET /docs → acme-docs (localhost:3001)
[proxy] GET /app → acme-dashboard (localhost:3002)
Common Issues
Proxy not starting: Check that every app lists @vercel/microfrontends as a dependency and that you start the apps through turbo. localProxyPort is optional and only changes the port.
Wrong app serves route: Your path pattern probably doesn't match what you think. Double-check the routing array.
Port 3024 already in use: Something else grabbed that port. Change localProxyPort or kill the other process.
Hybrid Local/Production Development
You don't need every app running. Start only the one you're working on:
pnpm turbo dev --filter=acme-marketingThe proxy still starts on localhost:3024. Requests for /docs/* and /app/* go to the default app's development.fallback, because child apps without their own fallback borrow the default app's. After you deploy in Lesson 2.5, that fallback is the marketing production domain, which routes those paths to the deployed docs and dashboard apps.
Give a child app its own development.fallback only when it should come from somewhere else, like a staging deployment. Until Lesson 2.5, run all three apps, since the fallback domain doesn't exist yet.
The proxy starts automatically on turbo dev with Turborepo 2.3.6, or 2.4.2 or newer.
Commit
git add -A
git commit -m "feat: configure local development proxy"Done-When
- All three apps running through proxy at
localhost:3024 - Navigation between apps works (/, /docs, /app)
- Each path serves content from the correct app
- You understand hybrid local/production development
What's Next
Notice the hard page reloads when navigating between apps. No shared client-side router. Next, you'll build shared packages for components that need to appear across all apps.
Was this helpful?