Overview
Next.js App Router uses a file-based routing system where the file structure in the app directory directly maps to URL routes. This approach simplifies routing configuration and provides better performance through automatic code splitting.
Route Segments Each folder in the app directory represents a route segment: app/
├── page.tsx # / (root route)
├── about/
│ └── page.tsx # /about
├── blog/
│ ├── page.tsx # /blog
│ └── [slug]/
│ └── page.tsx # /blog/[slug] (dynamic route)
└── dashboard/
├── page.tsx # /dashboard
└── settings/
└── page.tsx # /dashboard/settings
Special Files
page.tsx Makes a route publicly accessible Required for a route to be accessible Defines the UI for that route
layout.tsx Shared UI for multiple pages Wraps child layouts and pages Maintains state during navigation
loading.tsx Loading UI for a route segment Shows while page is loading Automatically wraps page and children
error.tsx Error UI for a route segment Catches errors in child segments Provides error boundaries
not-found.tsx 404 page for a route segment Shows when route is not found Can be nested at different levels
template.tsx Re-renders on every navigation Useful for animations and transitions Creates new instance for each route
Use parentheses to group routes without affecting the URL structure: app/
├── (auth)/
│ ├── login/
│ │ └── page.tsx # /login
│ └── register/
│ └── page.tsx # /register
├── (dashboard)/
│ ├── profile/
│ │ └── page.tsx # /profile
│ └── settings/
│ └── page.tsx # /settings
└── page.tsx # / (root)
Single Dynamic Segment app/
└── blog/
└── [slug]/
└── page.tsx # /blog/[slug]
// app/blog/[slug]/page.tsx
interface PageProps {
params : { slug : string };
}
export default function BlogPost ({ params } : PageProps ) {
return < h1 > Blog Post : {params. slug } </ h1 > ;
}
Multiple Dynamic Segments app/
└── shop/
└── [category]/
└── [product]/
└── page.tsx # /shop/[category]/[product]
// app/shop/[category]/[product]/page.tsx
interface PageProps {
params : {
category : string ;
product : string ;
};
}
export default function ProductPage ({ params } : PageProps ) {
return (
< div >
< h1 > Category : { params . category }</ h1 >
< h2 > Product : { params . product }</ h2 >
</ div >
);
}
Catch-All Routes app/
└── docs/
└── [...slug]/
└── page.tsx # /docs/[...slug]
// app/docs/[...slug]/page.tsx
interface PageProps {
params : { slug : string [] };
}
export default function DocsPage ({ params } : PageProps ) {
return < h1 > Docs : {params.slug.join( "/" )}</h1>;
}
Link Component import Link from "next/link" ;
export default function Navigation () {
return (
< nav >
< Link href = "/" > Home </ Link >
< Link href = "/about" > About </ Link >
< Link href = "/blog/hello-world" > Blog Post </ Link >
</ nav >
);
}
Programmatic Navigation "use client" ;
import { useRouter } from "next/navigation" ;
export default function MyComponent () {
const router = useRouter ();
const handleClick = () => {
router . push ( "/dashboard" );
// or
router . replace ( "/login" );
// or
router . back ();
};
return < button onClick ={ handleClick }> Navigate </ button > ;
}
Route Organization
Group Related Routes
Use route groups to organize related pages without affecting URLs
Use Descriptive Names
Choose clear, descriptive folder and file names
Keep Routes Flat
Avoid deeply nested routes when possible
Use Dynamic Routes Wisely
Use dynamic routes for content that changes frequently
Automatic Code Splitting Each route is automatically code-split Only loads code needed for current route Improves initial page load performance
Prefetching Links are automatically prefetched Improves navigation performance Can be disabled with prefetch=
Migration from React Router
Before (React Router) // App.js
import { BrowserRouter , Routes , Route } from "react-router-dom" ;
function App () {
return (
< BrowserRouter >
< Routes >
< Route path = "/" element = {<Home />} />
< Route path = "/about" element = {<About />} />
< Route path = "/blog/:slug" element = {<BlogPost />} />
</ Routes >
</ BrowserRouter >
);
}
After (Next.js App Router) app/
├── page.tsx # /
├── about/
│ └── page.tsx # /about
└── blog/
└── [slug]/
└── page.tsx # /blog/[slug]
Nested Layouts app/
├── layout.tsx # Root layout
├── dashboard/
│ ├── layout.tsx # Dashboard layout
│ ├── page.tsx # /dashboard
│ └── settings/
│ └── page.tsx # /dashboard/settings
Route Protection // app/dashboard/layout.tsx
import { redirect } from "next/navigation" ;
export default function DashboardLayout ({
children ,
} : {
children : React . ReactNode ;
}) {
// Check authentication
const isAuthenticated = checkAuth ();
if ( ! isAuthenticated ) {
redirect ( "/login" );
}
return (
< div >
< h1 > Dashboard </ h1 >
{ children }
</ div >
);
}
Problem : Route returns 404 even though file exists
Solution : Ensure the file is named page.tsx and is in the correct directory
Problem : Layout styles not showing on child routes Solution : Check
that layout.tsx is in the correct directory and wraps children
Dynamic Route Not Working
Problem : Dynamic route parameters not accessible
Solution : Ensure the page component receives params as props and handles the correct parameter names
Key Takeaway : Next.js file-based routing simplifies route management by
using the file system structure to define routes. This approach provides
better performance through automatic code splitting and makes routing more
intuitive for developers.