Next.js App Router: Server Components, Data, and Routing
Build modern Next.js applications with Server Components, nested layouts, route handlers, caching, metadata, and secure mutations.
How the App Router changes Next.js development
The App Router organizes a site with folders inside app. A folder becomes a URL segment when it contains a page file, while layout files provide shared UI that persists across navigation. Loading, error, not-found, and route files add behavior close to the route that uses it.
Components are Server Components by default. They can fetch data and access server-only resources without sending their JavaScript to the browser. Add the use client directive only when a component needs state, effects, browser APIs, or event handlers.
- page.tsx defines the UI for a route.
- layout.tsx wraps child routes and preserves shared state.
- loading.tsx provides an instant Suspense fallback.
- error.tsx handles rendering failures within a route segment.
- route.ts creates HTTP endpoints using Web Request and Response APIs.
Data fetching, caching, and mutations
Fetch data directly inside an async Server Component instead of adding a client-side effect by default. Independent requests should start together so one slow request does not create a waterfall.
For mutations, Server Actions let a form or client interaction call trusted server code. Validate input and authorize every action on the server. After a successful write, revalidate affected paths or tags so cached pages show fresh data.
export default async function Dashboard() {
const [profile, courses] = await Promise.all([
getProfile(),
getCourses(),
]);
return <DashboardView profile={profile} courses={courses} />;
}Dynamic routes and metadata
Use folders such as app/learn/[slug] for dynamic routes. The params value identifies the requested record, while generateStaticParams can prebuild known paths. Return notFound when the record does not exist.
Export static metadata for fixed pages or generateMetadata for content-driven titles, descriptions, canonical URLs, and social cards. Metadata should describe the specific route rather than repeat the site-wide default.
A practical performance checklist
- Keep interactive client boundaries small and pass serializable data into them.
- Use next/image for responsive images and next/font for stable font loading.
- Stream slow sections behind Suspense instead of blocking the whole page.
- Avoid fetching the same data again in a client component after rendering it on the server.
- Measure bundle size and Web Vitals before adding memoization or complex caching.
Key Takeaways
- Start with Server Components and opt into client rendering only for interaction.
- Fetch data near the route that needs it and parallelize independent work.
- Treat Server Actions as secured server endpoints.
- Use route-level loading, error, and metadata files to keep behavior maintainable.
Frequently Asked Questions
- Can Server Components use useState or useEffect?
- No. Move the interactive portion into a Client Component marked with use client, while keeping the surrounding data and layout on the server.
- When should I use a Route Handler instead of a Server Action?
- Use a Route Handler when external clients need an HTTP API, when you need custom HTTP methods or headers, or when the endpoint is not tied to a React mutation.
- Does every dynamic route need generateStaticParams?
- No. Use it when known paths benefit from build-time generation. Other paths can render dynamically according to the route's caching configuration.