Back to Blog
Understanding the Next.js App Router
2 min read

Understanding the Next.js App Router

The App Router is the biggest change to Next.js in years. Here is a practical mental model for how it actually works.

The App Router landed in Next.js 13 and has been stable since v14. If you've been putting off learning it, this post will give you a practical mental model for how it works and why it's worth the switch.

The fundamental shift: React Server Components

The App Router is built on React Server Components (RSC). This changes the default:

Pages RouterApp Router
DefaultClient ComponentServer Component
Data fetchinggetServerSideProps / getStaticPropsasync component functions
Client interactivityWhole pageOpt-in with "use client"

Server Components run on the server, can await data, and send only HTML to the browser. No JavaScript bundle. No hydration. Just content.

The file conventions

The App Router uses a folder-based convention:

app/
  layout.tsx      # Wraps all children — persists on navigation
  page.tsx        # The route itself
  loading.tsx     # Suspense fallback
  error.tsx       # Error boundary
  not-found.tsx   # 404 handler
  blog/
    page.tsx      # /blog
    [slug]/
      page.tsx    # /blog/:slug

When to use "use client"

You only need "use client" when you use:

  • React state (useState, useReducer)
  • React effects (useEffect)
  • Browser APIs (window, document)
  • Event handlers (onClick, onChange)

Everything else can — and should — stay on the server.

Nested layouts

The layout.tsx wraps its segment's subtree and persists across navigations in that segment. This means the navbar and sidebar don't re-render when you navigate between blog posts. Only the content changes.

Data fetching

// app/blog/[slug]/page.tsx
export default async function PostPage({ params }: { params: { slug: string } }) {
  const post = await fetchPost(params.slug); // runs on the server
  return <article>{post.content}</article>;
}

That's it. No getStaticProps, no useEffect, no loading state dance. Just async/await.

Conclusion

The App Router takes some getting used to, but once the mental model clicks — "Server by default, client by opt-in" — it's hard to go back. Start a new project with it and you'll see immediately how much simpler data fetching and layout composition become.

Ask AI about this post