---
title: "Path Routing Deep Dive"
description: "Understand how Vercel routes requests to microfrontends and why middleware behavior changes."
canonical_url: "https://vercel.com/academy/microfrontends-on-vercel/path-routing"
md_url: "https://vercel.com/academy/microfrontends-on-vercel/path-routing.md"
docset_id: "vercel-academy"
doc_version: "1.0"
last_updated: "2026-04-09T09:43:07.352Z"
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>

# Path Routing Deep Dive

# Path Routing Deep Dive

Microfrontends routing happens **before** your application code runs. This changes everything about how middleware, redirects, and rewrites behave.

## Outcome

Understand the routing execution order and how path isolation affects middleware, redirects, and rewrites.

## The Execution Order

When a request hits Vercel, it passes through these layers in order:

```
Request: GET /docs/api/overview

1. Firewall        → Platform-wide rules (DDoS, rate limiting)
2. MICROFRONTENDS  → Routes to correct project (/docs/* → docs app)
3. Headers         → Response headers for docs app
4. Redirects       → Redirect rules in docs app
5. Middleware      → Docs app middleware only
6. Rewrites        → Rewrite rules in docs app
7. Route Handler   → Actual page renders
```

**The key insight:** Microfrontends routing happens at step 2. By the time your middleware runs (step 5), the request has already been routed to a specific application.

## The Middleware Shift

This is the biggest conceptual change. Before microfrontends:

```typescript
// middleware.ts in monolith
export function middleware(request: NextRequest) {
  // This ran for EVERY request
  if (request.nextUrl.pathname.startsWith("/app")) {
    // Check auth
  }
}
```

After microfrontends:

```typescript
// middleware.ts in docs app
export function middleware(request: NextRequest) {
  // This ONLY runs for /docs/* requests
  // Requests to /app/* never reach this middleware
}
```

If you're used to a single central middleware for auth or logging, that pattern breaks. Each app's middleware only sees requests routed to that app.

## Path Isolation Explained

After microfrontends routing, each app is isolated:

| Request Path | Routed To | App Only Sees |
| ------------ | --------- | ------------- |
| `/`          | marketing | `/`           |
| `/pricing`   | marketing | `/pricing`    |
| `/docs`      | docs      | `/docs`       |
| `/docs/api`  | docs      | `/docs/api`   |
| `/app`       | dashboard | `/app`        |
| `/settings`  | dashboard | `/settings`   |

The docs app will **never** receive a request for `/pricing`. The marketing app will **never** see `/app/projects`.

## Fast Track

1. Review the execution order diagram above
2. Understand that each app only sees its own paths
3. Add a redirect to test path routing behavior

## Hands-on Exercise 2.2

Test path isolation by adding a redirect that crosses app boundaries.

### Part 1: Add a Cross-App Redirect

Add a redirect to `apps/marketing/next.config.ts`:

```typescript title="apps/marketing/next.config.ts"
import type { NextConfig } from "next";
import { withMicrofrontends } from "@vercel/microfrontends/next/config";

const nextConfig: NextConfig = {
  redirects: async () => [
    {
      source: "/documentation",
      destination: "/docs",
      permanent: true,
    },
  ],
};

export default withMicrofrontends(nextConfig);
```

### Part 2: Understand What Happens

When you visit `/documentation`:

1. Request arrives at Vercel
2. Microfrontends checks: does `/documentation` match any routing rules?
3. No match for `/docs/:path*` (different path), so it goes to marketing (default)
4. Marketing's redirect fires: `/documentation` → `/docs`
5. Browser makes new request for `/docs`
6. Microfrontends routes `/docs` to the docs app
7. Docs app serves the page

**Key insight:** The redirect works because `/documentation` routes to marketing first, where the redirect is defined.

### Part 3: What Would Break

If you added `/documentation` to the docs app's routing:

```json
"@acme/docs": {
  "routing": [
    { "paths": ["/docs", "/docs/:path*", "/documentation"] }
  ]
}
```

Now the redirect in marketing would **never run** because `/documentation` goes directly to docs. The redirect lives in marketing, but the path routes to docs.

## Try It

Start the apps and test the redirect:

```bash
pnpm dev
```

1. Visit **<http://localhost:3000/documentation>**
2. You should be redirected to `/docs`
3. The docs app serves the page

## Why Redirects Can "Disappear"

A common frustration: "I added a redirect, but it doesn't work!"

**The rule:** Redirects only run in the app that receives the request.

| Redirect Location | Path Routes To | Does Redirect Run? |
| ----------------- | -------------- | ------------------ |
| marketing         | marketing      | ✅ Yes              |
| marketing         | docs           | ❌ No               |
| docs              | docs           | ✅ Yes              |
| docs              | marketing      | ❌ No               |

If your redirect isn't working, check which app the path routes to.

## Debug Headers

In production, enable debug headers to see routing decisions:

| Header                              | Description                   |
| ----------------------------------- | ----------------------------- |
| `x-vercel-mfe-app`                  | Which app handled the request |
| `x-vercel-mfe-matched-path`         | Which pattern matched         |
| `x-vercel-mfe-target-deployment-id` | Deployment that served it     |

Enable debug mode:

1. Set cookie: `VERCEL_MFE_DEBUG=1`
2. Or use Vercel Toolbar → Microfrontends panel → Enable Debug Mode

We'll use these in Lesson 3.3 (Observability).

## Commit

```bash
git add -A
git commit -m "feat: add redirect to demonstrate path routing"
```

## Done-When

- [ ] You can explain the execution order: Firewall → MFE → Headers → Redirects → Middleware → Rewrites
- [ ] You understand that each app only sees requests for its own paths
- [ ] You know why redirects can "disappear" (defined in wrong app)
- [ ] You've tested the `/documentation` → `/docs` redirect

## The Pattern for Shared Logic

Since middleware is isolated per app, how do you share logic like authentication?

**Options:**

1. **Duplicate middleware** - Copy the same logic to each app (simple but redundant)
2. **Shared package** - Create `@acme/auth` with middleware helpers
3. **Server Components/Actions** - Move auth checks to `layout.tsx` or Server Actions (recommended in Next.js 16)

We'll implement the shared package approach in Lesson 2.4.

## What's Next

Enable the local proxy and see all three apps stitched together at `localhost:3024`.


---

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