Getting Started with the Next.js App Router
The App Router changes how you think about routing, layouts, and data fetching. Here's what you need to know to get productive fast.
The App Router is a fundamental shift in how Next.js works. Instead of a flat pages/ directory, you nest your UI inside app/ with co-located layouts, loading states, and error boundaries.
File Conventions
The App Router uses special filenames to determine behavior:
page.tsx— defines a route segmentlayout.tsx— shared UI that wraps child segmentsloading.tsx— Suspense fallbackerror.tsx— error boundarynot-found.tsx— 404 handler
Server Components by Default
Every component in app/ is a React Server Component unless you add "use client" at the top. This means:
- Zero JS sent to the browser for server-only UI
- Direct database / filesystem access inside components
- No need for
getServerSidePropsorgetStaticProps
// This runs on the server — you can read files, hit DBs, etc.
export default async function Page() {
const data = await db.query("SELECT * FROM posts");
return <ul>{data.map(row => <li key={row.id}>{row.title}</li>)}</ul>;
}
When to Use "use client"
Only add "use client" when you need:
useState,useEffect, or other hooks- Browser APIs (
window,document) - Event handlers that need interactivity
Keep client components at the leaves of your component tree. A common pattern: fetch data in a server component, pass it as props to a client component that handles interaction.
Data Fetching
The App Router uses native fetch with Next.js extensions for caching:
// Cached by default (like getStaticProps)
const data = await fetch("https://api.example.com/posts");
// Revalidate every 60 seconds (like ISR)
const data = await fetch("https://api.example.com/posts", {
next: { revalidate: 60 },
});
// No cache (like getServerSideProps)
const data = await fetch("https://api.example.com/posts", {
cache: "no-store",
});
Conclusion
The App Router takes some getting used to but the mental model is cleaner once it clicks. Start with server components, add client components only where interactivity is needed, and lean on the file conventions for layouts and loading states.