乐闻世界logo
搜索文章和话题

What are the key differences between Next.js App Router and Pages Router, and what is the migration strategy?

2月17日 23:33

Next.js 13+ introduced the all-new App Router, which has significant differences from the traditional Pages Router. The App Router is built on React Server Components, providing more powerful features and better performance.

Key Differences

1. File Structure

Pages Router:

shell
pages/ index.js about.js api/ users.js

App Router:

shell
app/ page.js about/ page.js api/ users/ route.js

2. Layout System

App Router's layout system is more powerful:

javascript
// app/layout.js import './globals.css'; export default function RootLayout({ children }) { return ( <html lang="en"> <body> <header>Global Header</header> {children} <footer>Global Footer</footer> </body> </html> ); } // app/about/layout.js export default function AboutLayout({ children }) { return ( <div className="about-layout"> <aside>About Sidebar</aside> <main>{children}</main> </div> ); }

3. Data Fetching Methods

Pages Router:

javascript
// pages/index.js export async function getServerSideProps() { const res = await fetch('https://api.example.com/data'); const data = await res.json(); return { props: { data } }; } export default function Home({ data }) { return <div>{data.title}</div>; }

App Router:

javascript
// app/page.js async function getData() { const res = await fetch('https://api.example.com/data', { next: { revalidate: 3600 } }); return res.json(); } export default async function Page() { const data = await getData(); return <div>{data.title}</div>; }

4. Server Components vs Client Components

App Router uses Server Components by default:

javascript
// app/page.js (Server Component - default) async function Page() { const data = await fetch('https://api.example.com/data').then(r => r.json()); return <div>{data.title}</div>; } export default Page; // app/components/Interactive.js (Client Component) 'use client'; import { useState } from 'react'; export default function Interactive() { const [count, setCount] = useState(0); return <button onClick={() => setCount(c => c + 1)}>{count}</button>; }

5. Route Parameters

Pages Router:

javascript
// pages/posts/[id].js export async function getStaticPaths() { const posts = await getAllPosts(); return { paths: posts.map(post => ({ params: { id: post.id } })), fallback: 'blocking' }; } export async function getStaticProps({ params }) { const post = await getPost(params.id); return { props: { post } }; }

App Router:

javascript
// app/posts/[id]/page.js export async function generateStaticParams() { const posts = await getAllPosts(); return posts.map(post => ({ id: post.id })); } export default async function PostPage({ params }) { const post = await getPost(params.id); return <article>{post.content}</article>; }

6. Loading States and Error Handling

App Router has built-in support:

javascript
// app/posts/loading.js export default function Loading() { return <div>Loading...</div>; } // app/posts/error.js 'use client'; export default function Error({ error, reset }) { return ( <div> <h2>Something went wrong!</h2> <button onClick={() => reset()}>Try again</button> </div> ); } // app/posts/not-found.js export default function NotFound() { return <div>Post not found</div>; }

7. Server Actions

App Router exclusive feature:

javascript
// app/actions.js 'use server'; import { revalidatePath } from 'next/cache'; export async function createPost(formData) { const title = formData.get('title'); const content = formData.get('content'); await savePost({ title, content }); revalidatePath('/posts'); } // app/posts/new/page.js import { createPost } from '../actions'; export default function NewPostPage() { return ( <form action={createPost}> <input name="title" /> <textarea name="content" /> <button type="submit">Create Post</button> </form> ); }

Migration Strategy

Progressive Migration

javascript
// Can use both Routers in the same project // pages/ - Old code continues using Pages Router // app/ - New features use App Router // Link from App Router to Pages Router <Link href="/old-page">Old Page</Link>

Key Migration Steps

  1. Install Next.js 13+ and update configuration
  2. Create app/ directory structure
  3. Migrate layouts to app/layout.js
  4. Gradually migrate pages to app/ directory
  5. Update data fetching logic
  6. Add 'use client' directive to interactive components
  7. Update API routes to Route Handlers
  8. Test and optimize performance

Performance Comparison

App Router Advantages:

  • Smaller client bundle (Server Components not sent to client)
  • Better SEO (default server-side rendering)
  • More flexible caching strategies
  • Built-in loading and error states
  • Cleaner code structure

Pages Router Advantages:

  • More mature and stable
  • Richer ecosystem and documentation
  • Simpler learning curve
  • More third-party library support

Best Practices

  1. New Projects: Prioritize App Router
  2. Existing Projects: Progressive migration, start with simple pages
  3. Component Selection: Use Server Components by default, only use Client Components when interaction is needed
  4. Data Fetching: Leverage fetch API caching options
  5. State Management: Use Server Actions to replace some API routes

The App Router represents the future direction of Next.js, providing a more modern development experience and better performance.

标签:Next.js