Next.js 14 App Router: A Complete Guide

DK

David Kim

December 28, 2023
12 min read
Next.js 14 App Router: A Complete Guide
Next.jsReactApp RouterPerformance

Next.js 14 App Router: A Complete Guide

Next.js 14 introduces significant improvements to the App Router, making it more powerful and developer-friendly. This guide covers everything from basic concepts to advanced patterns.

What's New in Next.js 14

Performance Improvements

  • Turbopack: Faster local development with Rust-based bundler
  • Server Actions: Simplified server-side mutations
  • Partial Prerendering: Combine static and dynamic content seamlessly

Developer Experience

  • Improved Error Handling: Better error messages and debugging
  • Enhanced TypeScript Support: Stricter type checking
  • Metadata API: Simplified SEO and social sharing setup

App Router Fundamentals

File-Based Routing

The App Router uses a file-system based router where folders define routes:

text
app/
  page.tsx          // /
  about/
    page.tsx        // /about
  blog/
    page.tsx        // /blog
    [slug]/
      page.tsx      // /blog/[slug]

Special Files

  • page.tsx: UI for a route segment
  • layout.tsx: Shared UI for multiple pages
  • loading.tsx: Loading UI
  • error.tsx: Error UI
  • not-found.tsx: 404 UI

Layouts and Templates

Root Layout

text
// app/layout.tsx
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body>
        <nav>Navigation</nav>
        {children}
        <footer>Footer</footer>
      </body>
    </html>
  );
}

Nested Layouts

text
// app/blog/layout.tsx
export default function BlogLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <div className="blog-layout">
      <aside>Blog Sidebar</aside>
      <main>{children}</main>
    </div>
  );
}

Server and Client Components

Server Components (Default)

text
// app/posts/page.tsx
async function getPosts() {
  const res = await fetch('https://api.example.com/posts');
  return res.json();
}

export default async function PostsPage() {
  const posts = await getPosts();
  
  return (
    <div>
      {posts.map(post => (
        <article key={post.id}>
          <h2>{post.title}</h2>
          <p>{post.excerpt}</p>
        </article>
      ))}
    </div>
  );
}

Client Components

text
'use client';

import { useState } from 'react';

export default function Counter() {
  const [count, setCount] = useState(0);
  
  return (
    <button onClick={() => setCount(count + 1)}>
      Count: {count}
    </button>
  );
}

Data Fetching Patterns

Parallel Data Fetching

text
async function getUser(id: string) {
  const res = await fetch(`/api/users/${id}`);
  return res.json();
}

async function getPosts(userId: string) {
  const res = await fetch(`/api/posts?userId=${userId}`);
  return res.json();
}

export default async function UserPage({ params }: { params: { id: string } }) {
  // These requests run in parallel
  const userPromise = getUser(params.id);
  const postsPromise = getPosts(params.id);
  
  const [user, posts] = await Promise.all([userPromise, postsPromise]);
  
  return (
    <div>
      <h1>{user.name}</h1>
      <PostsList posts={posts} />
    </div>
  );
}

Streaming with Suspense

text
import { Suspense } from 'react';

export default function Page() {
  return (
    <div>
      <h1>Dashboard</h1>
      <Suspense fallback={<div>Loading analytics...</div>}>
        <Analytics />
      </Suspense>
      <Suspense fallback={<div>Loading posts...</div>}>
        <RecentPosts />
      </Suspense>
    </div>
  );
}

Server Actions

Form Handling

text
// app/contact/page.tsx
async function submitForm(formData: FormData) {
  'use server';
  
  const name = formData.get('name') as string;
  const email = formData.get('email') as string;
  
  // Process form data
  await saveContact({ name, email });
  
  redirect('/thank-you');
}

export default function ContactPage() {
  return (
    <form action={submitForm}>
      <input name="name" placeholder="Name" required />
      <input name="email" type="email" placeholder="Email" required />
      <button type="submit">Submit</button>
    </form>
  );
}

Advanced Patterns

Route Groups

text
app/
  (marketing)/
    about/
      page.tsx      // /about
    contact/
      page.tsx      // /contact
  (shop)/
    products/
      page.tsx      // /products

Parallel Routes

text
app/
  dashboard/
    @analytics/
      page.tsx
    @team/
      page.tsx
    layout.tsx
    page.tsx

Intercepting Routes

text
app/
  feed/
    page.tsx
    @modal/
      (..)photo/
        [id]/
          page.tsx    // Intercepts /photo/[id]

Migration from Pages Router

Key Differences

  1. File Structure: pages/app/
  2. API Routes: pages/api/app/api/
  3. Data Fetching: getServerSideProps → Server Components
  4. Layouts: HOCs → layout.tsx files

Migration Strategy

  1. Start with new routes in app/
  2. Gradually migrate existing pages
  3. Update data fetching patterns
  4. Refactor layouts and components

Best Practices

  1. Use Server Components by Default: Only use Client Components when needed
  2. Colocate Related Files: Keep components, styles, and tests together
  3. Optimize Loading States: Use Suspense boundaries strategically
  4. Handle Errors Gracefully: Implement proper error boundaries
  5. Leverage Caching: Understand Next.js caching behavior

Conclusion

Next.js 14's App Router represents a significant evolution in React development. By embracing Server Components, improved data fetching, and modern patterns, you can build faster, more maintainable applications. The learning curve is worth the investment for the performance and developer experience benefits.

The App Router isn't just a new routing system—it's a new way of thinking about React applications.

Read Next

Web Accessibility: A Developer's Guide
20 Dec 2023
15 min read

Learn how to build inclusive web applications that work for everyone, including users with disabilities.

GraphQL vs REST: Making the Right Choice
4 Jan 2024
7 min read

A detailed comparison of GraphQL and REST APIs to help you choose the right approach for your project.

State Management in Modern React Applications
26 Dec 2023
10 min read

Comprehensive guide to choosing and implementing state management solutions in React applications.