Architecture Patterns
Two ways to split a frontend: by page or by component.
Outcome
Understand vertical vs horizontal microfrontends and know which pattern fits which use case.
Vertical Microfrontends (Multi-Zones)
Vertical microfrontends split by path. Each page is handled by exactly one application.
┌─────────────────────────────────────┐
│ vercel.com domain │
├─────────────────────────────────────┤
│ / → Marketing App │
│ /pricing → Marketing App │
│ /docs/* → Docs App │
│ /app/* → Dashboard App │
│ /settings/* → Dashboard App │
└─────────────────────────────────────┘
When you visit /docs/api, the Vercel proxy routes that request directly to the Docs application. The Marketing and Dashboard apps never see it.
Use vertical when:
- Users don't frequently cross between areas
- Each area has a distinct user interface
- Different teams own different sections
- You want independent deployments per section
Real examples:
- Vercel: marketing, docs, dashboard (12 projects total)
- Large e-commerce: storefront, checkout, account management
Horizontal Microfrontends (Remote Components)
Horizontal microfrontends split by feature. Multiple applications contribute to the same page.
┌─────────────────────────────────────┐
│ Single Page │
├─────────────────────────────────────┤
│ ┌─────────────────────────────┐ │
│ │ Header (App A) │ │
│ └─────────────────────────────┘ │
│ ┌─────────────────────────────┐ │
│ │ Hero Section (App B) │ │
│ └─────────────────────────────┘ │
│ ┌─────────────────────────────┐ │
│ │ Footer (App C) │ │
│ └─────────────────────────────┘ │
└─────────────────────────────────────┘
A header component from one application renders inside a page owned by another application. This happens at runtime, not build time.
Use horizontal when:
- The same component appears across many pages
- Different teams own different UI sections on the same page
- You need runtime flexibility (update without redeploying host)
Real examples:
- Shared header/footer across a portfolio of sites
- Embedded widgets from different teams
Important distinction: Not every shared component needs microfrontends. If your teams can coordinate releases, shared components via private NPM packages or monorepo packages (like the shared UI package you'll build in this course) work well and carry zero runtime overhead. Reserve horizontal microfrontends for cases where you need runtime independence — updating a component without redeploying every app that uses it.
Vercel's remote components (horizontal) are in alpha. This course focuses on vertical, which is GA.
Comparing the Patterns
| Aspect | Vertical | Horizontal |
|---|---|---|
| Split by | Path/page | Component/feature |
| Navigation | Hard (full page load) | Soft (client-side) |
| Complexity | Lower | Higher |
| State sharing | URL, cookies | Shared context, modules |
| Status | GA | Alpha |
How Vercel's Proxy Works
Independent apps need a coordinator. Back to the food truck lot: someone owns the lot, directs customers to the right truck, and keeps the trucks from blocking each other. Vercel's proxy plays that role — it routes each request to the right application before your code runs:
Request: GET /docs/api/overview
┌──────────────────────────────────────────────┐
│ Vercel Proxy │
├──────────────────────────────────────────────┤
│ 1. Firewall rules (default app) │
│ 2. Microfrontends routing │
│ → matches /docs/:path* → routes to docs │
│ 3. Docs app receives request │
│ 4. Docs app's own routing rules execute │
└──────────────────────────────────────────────┘
This proxy-level routing provides:
- 25% latency savings compared to middleware-based routing
- Complete isolation between applications
- No route trampling - apps can't accidentally override each other
Fast Track
- Review the comparison table above
- Confirm vertical is right for your use case
- Sketch your application's zone boundaries
Hands-on Exercise 1.2
Map the Acme Platform to vertical zones.
Requirements:
- Draw the routing diagram for Acme Platform
- Identify which app is the "default" (catches unmatched routes)
- List the exact path patterns for each child app
Your Routing Map:
Fill in the blanks:
┌─────────────────────────────────────┐
│ acme-platform.com domain │
├─────────────────────────────────────┤
│ / → ___________ App │
│ /pricing → ___________ App │
│ /about → ___________ App │
│ /docs → ___________ App │
│ /docs/* → ___________ App │
│ /app → ___________ App │
│ /app/* → ___________ App │
│ /settings/* → ___________ App │
└─────────────────────────────────────┘
Solution
┌─────────────────────────────────────┐
│ acme-platform.com domain │
├─────────────────────────────────────┤
│ / → Marketing App │ (default)
│ /pricing → Marketing App │ (default)
│ /about → Marketing App │ (default)
│ /docs → Docs App │ (child)
│ /docs/* → Docs App │ (child)
│ /app → Dashboard App │ (child)
│ /app/* → Dashboard App │ (child)
│ /settings/* → Dashboard App │ (child)
└─────────────────────────────────────┘
Key decisions:
- Marketing is default - It catches all unmatched routes (404 pages live here)
- Docs owns
/docs/*- Single path pattern covers all documentation - Dashboard owns
/app/*AND/settings/*- Two path patterns, one application
Done-When
- You can explain vertical vs horizontal microfrontends
- You've mapped Acme Platform to three vertical zones
- You understand why Marketing is the default application
- You know that microfrontends routing happens before middleware
The Isolation Principle
Here's the key insight: after microfrontends routing, each app only sees its own paths.
The Docs app will never receive a request for /pricing. The Dashboard app will never see /docs/api. This isolation is powerful. But it means shared logic (like authentication) must exist in each app that needs it.
We'll address this challenge in Section 2 when we build shared packages.
What's Next
Time to build. You'll set up a Turborepo monorepo for the applications.
Was this helpful?