Next.js Architecture Diagram: App Router, Rendering, and Deployment
A version-aware Next.js architecture diagram covering App Router boundaries, RSC payloads, caching, navigation, and deployment decisions.
Direct answer: the diagram below describes a current Next.js App Router application. It shows the browser, the Server and Client Component boundary, build-time and request-time rendering, the RSC Payload and HTML response, navigation and prefetching, caching and revalidation, and the deployment runtime. Next.js also supports the older Pages Router, so label any diagram with the router, installed version, and cache configuration it represents.
Next.js is a React framework for full-stack web applications. The App Router uses newer React capabilities; the Pages Router remains supported. The architecture is not one fixed stack: a route can be statically rendered, dynamically rendered, or composed from cached and deferred parts depending on its components, APIs, configuration, and deployment topology. See the Next.js documentation for version-specific behavior.
1. The complete App Router architecture diagram
┌──────────────────────────────┐
│ Browser │
│ HTML + hydrated Client │
│ Components + router cache │
└──────────────┬───────────────┘
│ initial request
│ navigations / RSC Payload
▼
┌────────────────────────────────────────────────────────────────────┐
│ Next.js application │
│ │
│ ┌──────────────────────┐ ┌───────────────────────────────┐ │
│ │ App Router route tree │ │ Rendering paths │ │
│ │ layouts / pages │──────▶│ • build or revalidation time │ │
│ │ Server Components │ │ • request-time dynamic render │ │
│ │ Client boundaries │ │ • streaming and transitions │ │
│ └──────────────────────┘ └───────────────┬───────────────┘ │
│ │ │
│ ┌──────────────────────────────┴───────────────┐ │
│ │ Server Component render │ │
│ │ RSC Payload + HTML pre-render for first load │ │
│ └──────────────────────────────┬───────────────┘ │
│ │ │
│ ┌──────────────────────┐ ┌─────────────┴───────────────┐ │
│ │ Cache / revalidation │◀──────│ Data sources and server code │ │
│ │ static, cached, │ │ databases, APIs, files │ │
│ │ uncached, tagged │ └─────────────────────────────┘ │
│ └──────────────────────┘ │
└────────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────────────────────────┐
│ Deployment runtime │
│ Node.js server / platform adapter │
│ reverse proxy, shared cache, CDN │
└─────────────────────────────────────┘
Read the two initial-load outputs separately:
| Output | Purpose |
|---|---|
| HTML | Lets the browser display the initial page before all client JavaScript is ready. |
| RSC Payload | Describes the rendered Server Component tree, Client Component references, and serializable props so React can reconcile the tree. |
2. App Router versus Pages Router
| Question | App Router | Pages Router |
|---|---|---|
| Route location | app/ directory with layouts and pages |
pages/ directory |
| Default component model | Layouts and pages are Server Components by default | Uses the Pages Router data-fetching and rendering model |
| Client interactivity | Add a use client boundary where state, events, lifecycle behavior, or browser APIs are needed |
Client-side React behavior is organized through the page model |
| Diagram label | Show RSC Payload, Server/Client boundaries, and App Router navigation | Do not imply App Router internals apply unchanged |
Pages Router applications remain supported. Before documenting an existing project, inspect its directory structure and installed Next.js version instead of copying an App Router diagram onto it.
3. Server Components and Client Components
In the App Router, layouts and pages are Server Components unless a module enters a client boundary. Server Components can fetch data and produce the RSC Payload without sending their implementation to the browser. Use Client Components for state, event handlers, lifecycle behavior, and browser APIs.
// app/products/page.tsx — Server Component by default
import AddToCart from './AddToCart'
export default async function ProductsPage() {
const products = await fetch('https://example.com/api/products').then(r => r.json())
return (
<main>
{products.map((product: { id: string; name: string }) => (
<AddToCart key={product.id} product={product} />
))}
</main>
)
}
// app/products/AddToCart.tsx — Client Component
'use client'
import { useState } from 'react'
export default function AddToCart({ product }: { product: { id: string; name: string } }) {
const [added, setAdded] = useState(false)
return (
<button onClick={() => setAdded(true)}>
{added ? 'Added' : `Add ${product.name}`}
</button>
)
}
The use client directive creates a client module-graph boundary. Imports and descendants below that boundary contribute to the client bundle. Keep the boundary as deep as practical so interactive code does not pull unrelated server-rendered code into the browser.
4. Initial request and hydration flow
- The browser requests a route.
- Next.js renders the Server Component tree into an RSC Payload.
- Next.js uses that payload and Client Component references to pre-render HTML for the initial visit.
- The browser displays the HTML.
- React reconciles the HTML with the RSC Payload and hydrates Client Components, attaching event handlers and browser behavior.
These are related but distinct stages. A diagram that labels everything as a single “page response” hides the reason Server Components can send less client JavaScript while still supporting interactive islands.
5. Navigation, prefetching, and streaming
Later navigation is different from the first visit. A client-side transition can request a prefetched or newly rendered RSC Payload, update the route tree, and preserve layouts that do not need to change. By default, Link can prefetch routes when links enter the viewport. Streaming allows parts of a response to arrive progressively when relevant features and the deployment path support it. These mechanisms improve perceived responsiveness, but they are not universal speed guarantees.
// app/page.tsx
import Link from 'next/link'
export default function Home() {
return (
<nav>
<Link href="/dashboard">Dashboard</Link>
</nav>
)
}
6. Rendering modes and the cache boundary
Next.js can prerender a route at build time or during revalidation, or render it at request time. Static rendering and caching are common defaults, but dynamic APIs and explicit configuration can change the result.
| Path | When it runs | Typical reason |
|---|---|---|
| Build-time prerender | During production build | Content is known ahead of time. |
| Revalidation | After a configured interval or invalidation | Refresh data without rebuilding the whole application. |
| Request-time dynamic rendering | For an incoming request | Output depends on cookies, search parameters, headers, or other request data. |
| Streaming | While a response is being produced | Send available UI progressively when the runtime supports it. |
Dynamic APIs such as cookies and request-dependent search parameters can opt rendering into dynamic behavior. Cache Components are documented as an opt-in feature that can combine a static shell with cached or deferred dynamic content. Confirm the installed Next.js version and configuration before drawing Cache Components or Partial Prerendering as a guaranteed part of a project.
Next.js documentation describes the static/dynamic boundary at the component level rather than the route level. Therefore, a route diagram should show which components are cached, uncached, deferred, or request-dependent instead of coloring an entire route only “static” or “dynamic.”
7. Data fetching and server boundaries
Server Components can fetch directly from data sources. Do not assume every application contains a separate backend service, and do not add a Route Handler hop solely because the code runs on the server. A Route Handler is appropriate when an external client needs an HTTP endpoint; a Server Component can generally call its data source directly.
// app/reports/page.tsx
export default async function ReportsPage() {
const response = await fetch('https://example.com/api/reports', {
next: { revalidate: 300 },
})
if (!response.ok) throw new Error('Unable to load reports')
const reports = await response.json()
return <pre>{JSON.stringify(reports, null, 2)}</pre>
}
The exact cache behavior depends on the installed version, fetch options, dynamic APIs, and project configuration. Treat the snippet as a shape for the data path, not as a promise that every fetch is cached.
8. Deployment topology
The current deployment guide lists a Node.js server as the minimum platform requirement for the described Next.js features. A single next start process can handle the application, while production deployments may add a reverse proxy, CDN, and shared cache.
# production build and start
npm run build
npm run start
For self-hosting:
- Put a reverse proxy in front of the Next.js server, as recommended by the self-hosting guide.
- Ensure the deployment path supports streaming when you depend on progressive Server Component delivery.
- Use shared cache and tag coordination for multi-instance consistency.
- Remember that a tag invalidation on one instance does not automatically invalidate other instances unless the instances share invalidation state.
- Draw edge stitching or platform adapters only when your chosen platform documents support for the features you use.
A useful deployment diagram separates the Next.js runtime from infrastructure concerns: reverse proxy, CDN, cache, process replicas, and data sources. Do not label a generic edge runtime as interchangeable with a Node.js server without checking the platform feature matrix.
9. How to make your own architecture diagram
- Write “App Router” or “Pages Router” and the Next.js version in the title.
- Draw the browser and label initial HTML, RSC Payload, hydration, and later client transitions.
- Draw layouts and pages inside the Next.js runtime.
- Mark Server Components as the default and place explicit Client Component boundaries around interactive code.
- Split rendering into build/revalidation and request-time paths.
- Connect server code to databases, APIs, and files without inventing a mandatory backend tier.
- Add cache and revalidation behavior beside the components or data reads it affects.
- Add the deployment runtime, reverse proxy, and shared cache only when they exist in the target topology.
- Annotate version-sensitive features such as Cache Components, adapters, and streaming support.
Or skip the browser setup
If you need a rendered image of a documentation page or diagram, ScreenshotNeo provides a single-call screenshot API. Cookie banners, newsletter popups, and chat widgets are removed before the shot. Bot checks, blank pages, failed loads, timeouts, and cache hits are not billed, and the response identifies the page verdict and billing result.
See the ScreenshotNeo API docs for all options. This cURL request returns a WebP screenshot:
curl -G "https://api.screenshotneo.com/v1/shot" -d access_key=YOUR_API_KEY --data-urlencode url=https://stripe.com -o shot.webp
import requests
r = requests.get("https://api.screenshotneo.com/v1/shot", params={"access_key": "YOUR_API_KEY", "url": "https://stripe.com"}, timeout=90)
open("shot.webp", "wb").write(r.content)
const q = new URLSearchParams({ access_key: 'YOUR_API_KEY', url: 'https://stripe.com' });
const res = await fetch(`https://api.screenshotneo.com/v1/shot?${q}`);
ScreenshotNeo also has an MCP server with take_screenshot, get_page_info, and capture_pdf tools for Claude, Cursor, and other MCP clients. It includes full-page capture, element selection, dark mode, device presets, custom CSS and JavaScript, waits, request blocking, cookies and headers, geolocation, caching, signed links, asynchronous jobs, bulk capture, and a usage API. The free plan includes 1,000 screenshots per month with no card; paid plans start at $5 for 3,000. Create a free ScreenshotNeo account.
10. Troubleshooting an architecture diagram
| Symptom | Likely cause | Fix |
|---|---|---|
| Interactive code fails during build | A Server Component uses browser-only APIs or event handlers. | Move the interactive portion behind a use client boundary. |
| The client bundle is unexpectedly large | A high-level client boundary imports many descendants. | Move use client deeper and keep data-heavy UI on the server. |
| Personalized output is cached | The diagram assumes static rendering despite request-dependent data. | Review cookies, headers, search parameters, fetch options, and explicit cache configuration. |
| Data is stale on one replica | Instances do not share cache or tag invalidation state. | Configure shared cache and coordinated invalidation, or reduce the topology. |
| Streaming does not appear | A proxy or hosting adapter buffers responses, or the feature is unsupported. | Check the deployment feature matrix and proxy buffering configuration. |
| A Pages Router diagram does not match the code | The project was documented as App Router. | Inspect whether routes live under app/ or pages/, then redraw with the matching model. |
| A screenshot contains a consent banner | The capture tool loaded the page exactly as a fresh browser session. | Use ScreenshotNeo’s consent and popup removal options, or handle the banner in your own browser automation. |
11. Performance, reliability, and cost considerations
- Performance: Keep client boundaries narrow, use prefetching and client transitions where appropriate, and stream only through infrastructure that supports it. Avoid treating static rendering or prefetching as a universal latency guarantee.
- Reliability: Version the diagram, document dynamic APIs and cache invalidation, and test the actual deployment topology. Multi-instance cache behavior needs coordination.
- Operational cost: Build-time and cached work can reduce repeated origin computation, while request-time rendering consumes runtime capacity. The right split depends on freshness, personalization, and infrastructure.
- Screenshot cost: ScreenshotNeo bills only clean shots. Bot checks, blank pages, timeouts, failed loads, and cache hits cost nothing, and each response includes
X-Page-VerdictandX-Billedheaders.
12. FAQ
Is every Next.js page a Server Component?
In the App Router, layouts and pages are Server Components by default. A use client directive creates a client boundary for the module graph below it.
Does the browser receive the RSC Payload on the first request?
Yes. The server renders the Server Component tree into an RSC Payload and also pre-renders HTML for the initial visit. The browser uses both during reconciliation and hydration.
Should an architecture diagram always include a database?
Only if the application uses one. Next.js Server Components can fetch from APIs, databases, files, or other data sources; no separate backend service is mandatory.
When should I draw a CDN or edge runtime?
When the selected deployment platform and application actually use it. Confirm support for streaming, caching, and adapters before adding those paths to a version-specific diagram.
Can I capture the diagram as a PDF?
Yes. ScreenshotNeo includes PDF capture through its API and MCP server, with controls for paper size, margins, landscape mode, and page ranges.
Sources: Server and Client Components, Linking and Navigating, Production Checklist, Cache Components, Deploying to Platforms, and Self-Hosting.


