Skip to main content

Introduction to App Router

The App Router is the modern routing system in NextJS, introduced in NextJS 13. It uses the app/ directory and provides enhanced features:
  • Nested layouts - Share UI across routes
  • Server Components by default - Better performance
  • Streaming - Progressive rendering
  • Built-in loading and error states - Better UX
The App Router (app/ directory) and Pages Router (pages/ directory) can coexist, but App Router takes precedence when both exist.

Project Structure

In the App Router, every folder is a route segment, and special files define the UI:
app/
├── layout.js          # Root layout (required)
├── page.js            # Home page (/)
├── about/
│   └── page.js        # About page (/about)
└── blog/
    ├── page.js        # Blog list (/blog)
    └── [slug]/
        └── page.js    # Blog post (/blog/post-1)
Only page.js files are publicly accessible as routes. Other files like layout.js, loading.js, and error.js are special UI files.

Root Layout

Every App Router application must have a root layout.js:
app/layout.js
import './globals.css'

export const metadata = {
  title: 'NextJS Course App',
  description: 'Your first NextJS app!',
};

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  );
}
  • Required - Every app needs a root layout
  • Must contain <html> and <body> tags
  • Can export metadata for SEO
  • Shared across all pages
  • Does not re-render on navigation

Creating Pages

Create routes by adding page.js files:
app/page.js
import Link from 'next/link';

export default function Home() {
  return (
    <main>
      <img src="/logo.png" alt="A server surrounded by magic sparkles." />
      <h1>Welcome to this NextJS Course!</h1>
      <p>Let's get started!</p>
      <p><Link href="/about">About Us</Link></p>
    </main>
  );
}

Multiple Routes

app/about/page.js
export default function AboutPage() {
  return (
    <main>
      <h1>About Us</h1>
      <p>Learn more about our NextJS course.</p>
    </main>
  );
}

/

app/page.js

/about

app/about/page.js

/blog

app/blog/page.js

/blog/[slug]

app/blog/[slug]/page.js
Use the Link component for client-side navigation:
import Link from 'next/link';

export default function Navigation() {
  return (
    <nav>
      <Link href="/">Home</Link>
      <Link href="/about">About</Link>
      <Link href="/blog">Blog</Link>
    </nav>
  );
}
Link provides:
  • Client-side navigation (no full page reload)
  • Automatic prefetching in viewport
  • Smooth transitions between routes
  • Browser history support

Dynamic Routes

Create dynamic segments using square brackets:
app/blog/[slug]/page.js
export default function BlogPostPage({ params }) {
  return (
    <main>
      <h1>Blog Post</h1>
      <p>{params.slug}</p>
    </main>
  );
}

Accessing Route Parameters

The params prop contains dynamic route parameters:
export default function BlogPostPage({ params }) {
  console.log(params.slug); // "my-first-post"
  return <h1>{params.slug}</h1>;
}

Nested Layouts

Create layouts for specific route segments:
app/meals/layout.js
export default function MealsLayout({ children }) {
  return (
    <>
      <nav>
        <Link href="/meals">All Meals</Link>
        <Link href="/meals/share">Share Meal</Link>
      </nav>
      <main>{children}</main>
    </>
  );
}
Layouts wrap all child pages and nested layouts. Navigation between pages within a layout does not re-render the layout.

Building a Complete App: Foodies

Let’s examine a real example from the course - a food sharing application:
app/page.js
import Link from 'next/link';
import ImageSlideshow from '@/components/images/image-slideshow';
import classes from './page.module.css';

export default function Home() {
  return (
    <>
      <header className={classes.header}>
        <div className={classes.slideshow}>
          <ImageSlideshow />
        </div>
        <div>
          <div className={classes.hero}>
            <h1>NextLevel Food for NextLevel Foodies</h1>
            <p>Taste & share food from all over the world.</p>
          </div>
          <div className={classes.cta}>
            <Link href="/community">Join the Community</Link>
            <Link href="/meals">Explore Meals</Link>
          </div>
        </div>
      </header>
      <main>
        <section className={classes.section}>
          <h2>How it works</h2>
          <p>
            NextLevel Food is a platform for foodies to share their favorite
            recipes with the world. It's a place to discover new dishes, and to
            connect with other food lovers.
          </p>
        </section>

        <section className={classes.section}>
          <h2>Why NextLevel Food?</h2>
          <p>
            NextLevel Food is a platform for foodies to share their favorite
            recipes with the world.
          </p>
        </section>
      </main>
    </>
  );
}

CSS Modules

NextJS supports CSS Modules out of the box:
page.module.css
.header {
  display: flex;
  gap: 3rem;
  padding: 3rem;
}

.hero h1 {
  font-size: 2rem;
  font-weight: bold;
}

.cta a {
  padding: 1rem 2rem;
  border-radius: 0.5rem;
}
  • Scoped styles - No naming conflicts
  • Automatic optimization - Unused styles removed
  • Type-safe - Import as JavaScript object
  • Co-located - Keep styles with components

Image Optimization

Use the Image component for automatic optimization:
import Image from 'next/image';

export default function MealItem({ meal }) {
  return (
    <article>
      <Image
        src={meal.image}
        alt={meal.title}
        fill
        sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
      />
      <h2>{meal.title}</h2>
    </article>
  );
}

Lazy Loading

Images load as they enter viewport

Size Optimization

Automatic WebP/AVIF format conversion

Responsive

Serves correct size for device

Blur Placeholder

Smooth loading experience

Route Organization

1

Create Route Folders

Each folder represents a URL segment
2

Add page.js

Make the route publicly accessible
3

Add layout.js (Optional)

Share UI across child routes
4

Add Special Files

Include loading.js, error.js, not-found.js as needed

Key Differences: Pages vs App Router

FeaturePages RouterApp Router
Directorypages/app/
RoutesFile-basedFolder-based
Data FetchinggetServerSidePropsasync components
DefaultClient ComponentsServer Components
Layouts_app.jslayout.js
Loading StatesCustomloading.js
Error Handling_error.jserror.js

Next Steps

Server Components

Learn about React Server Components

Server Actions

Handle form submissions and mutations

Build docs developers (and LLMs) love