---
title: "MFE Local Development"
description: "Run multiple microfrontends locally through the development proxy at localhost:3024."
canonical_url: "https://vercel.com/academy/microfrontends-on-vercel/mfe-local-development"
md_url: "https://vercel.com/academy/microfrontends-on-vercel/mfe-local-development.md"
docset_id: "vercel-academy"
doc_version: "1.0"
last_updated: "2026-11-04T22:26:55.231Z"
content_type: "lesson"
course: "microfrontends-on-vercel"
course_title: "Microfrontends on Vercel"
prerequisites:  []
---

<agent-instructions>
Vercel Academy — structured learning, not reference docs.
Lessons are sequenced.
Adapt commands to the human's actual environment (OS, package manager, shell, editor) — detect from project context or ask, don't assume.
The lesson shows one path; if the human's project diverges, adapt concepts to their setup.
Preserve the learning goal over literal steps.
Quizzes are pedagogical — engage, don't spoil.
Quiz answers are included for your reference.
</agent-instructions>

# MFE Local Development

# 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

1. Add `localProxyPort` to microfrontends.json
2. Run `pnpm dev` from the root
3. Visit `localhost:3024` to 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`:

```json title="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:

```bash
pnpm dev
```

You 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.

1. **Marketing homepage loads** - You're at `/` served by marketing app
2. **Click "Docs" in the header** - Navigates to `/docs` served by docs app
3. **Click "Dashboard" in the header** - Navigates to `/app` served by dashboard app
4. **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:

1. Open DevTools → Network
2. Visit `localhost:3024/docs`
3. Look at the request - it's to `localhost:3024/docs`
4. 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](https://vercel.com/docs/microfrontends/local-development#debug-routing). 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:

```bash
pnpm turbo dev --filter=acme-marketing
```

The 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

```bash
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.


---

[Full course index](/academy/llms.txt) · [Sitemap](/academy/sitemap.md)
