Featured image of post Next.js App Router 基础 and Migration 技巧Featured image of post Next.js App Router 基础 and Migration 技巧

Next.js App Router 基础 and Migration 技巧

A guide to Next.js App Router fundamentals, covering routing design concepts for developers planning to migrate.

Introduced in Next.js 13, the App Router takes a fundamentally different approach to routing and rendering compared to the traditional Pages Router. Now stable and widely adopted, let’s break down the basics for those planning to migrate.

App Router vs Pages Router

FeaturePages RouterApp Router
RoutingUnder pages/Under app/
ComponentsClient Component by defaultServer Component by default
LayoutsManual implementationNestable layout.js
LoadingManual implementationAutomatic via loading.js
Data FetchinggetServerSideProps, etc.Direct async inside components

1. File-Based Routing

Folder structure inside app/ maps directly to URL paths.

app/
├── page.js          → /
├── layout.js        → Shared layout for all pages
├── about/
│   └── page.js      → /about
└── blog/
    ├── page.js      → /blog
    └── [slug]/
        └── page.js  → /blog/hello-world (dynamic route)
// app/blog/[slug]/page.js
export default async function BlogPost({ params }) {
  const { slug } = await params;
  const post = await getPost(slug);
  return <article>{post.title}</article>;
}

2. Layout System

layout.js automatically applies to all pages under its folder. Layouts can be nested.

// app/layout.js (root layout)
export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>
        <header>Site Header</header>
        {children}
        <footer>Site Footer</footer>
      </body>
    </html>
  );
}
// app/blog/layout.js (blog section layout)
export default function BlogLayout({ children }) {
  return (
    <div className="blog-wrapper">
      <aside>Sidebar</aside>
      <main>{children}</main>
    </div>
  );
}

3. Loading and Error States

Drop loading.js and error.js into a folder to automatically get loading and error UIs.

// app/blog/loading.js
export default function Loading() {
  return <div>Loading...</div>;
}
// app/blog/error.js
'use client';
export default function Error({ error, reset }) {
  return (
    <div>
      <h2>Something went wrong</h2>
      <button onClick={reset}>Try again</button>
    </div>
  );
}

4. Server vs Client Components

In App Router, Server Components are the default — this is the key change.

Server ComponentClient Component
Renders onServerBrowser
useState / useEffect❌ Not available✅ Available
Direct DB access✅ Possible❌ Not possible
Bundle sizeSmall (no JS sent)Large
Interactions❌ Not possible✅ Possible
// Server Component (default) — can access DB directly
export default async function PostList() {
  const posts = await db.query('SELECT * FROM posts');
  return <ul>{posts.map(p => <li key={p.id}>{p.title}</li>)}</ul>;
}

Rule of thumb: write Server Components by default, and only use Client Components for the smallest interactive pieces.

5. Data Fetching Patterns

App Router lets you call fetch() directly inside components. Caching is on by default.

// Cached (default)
const data = await fetch('https://api.example.com/posts');

// No cache (fresh every request)
const data = await fetch('https://api.example.com/posts', {
  cache: 'no-store',
});

// Time-based revalidation
const data = await fetch('https://api.example.com/posts', {
  next: { revalidate: 60 },
});

6. Route Groups

Wrap a folder name in ( ) to organize files without affecting the URL.

app/
├── (marketing)/
│   ├── page.js      → /
│   └── pricing/
│       └── page.js  → /pricing
└── (shop)/
    ├── layout.js    → Shop-specific layout
    └── products/
        └── page.js  → /products

Great for using different layouts across sections without URL prefixes.

摘要

App Router is a new architecture centered around Server Components, and its philosophy differs significantly from Pages Router. It may be confusing at first, but sticking to “Server Components first, Client Components only where needed” will lead to high-performance applications. For migrations, start with smaller pages and move gradually.