Pages and Routing
Next.js Development
Pages and Routing
Next.js uses a file-system-based routing mechanism where the file and folder structure inside the app directory automatically maps to URL paths. Each folder represents a route segment, and a page.tsx file inside a folder makes that route publicly accessible. This eliminates the need for a separate routing configuration file and makes the relationship between URLs and code immediately visible in the project structure. Next.js routing supports dynamic segments, catch-all routes, route groups, and parallel routes for complex application architectures.
Basic File-Based Routing
Every page.tsx file in the app directory creates a route. The file path determines the URL path.
// File structure → URL mapping
// app/page.tsx → /
// app/about/page.tsx → /about
// app/contact/page.tsx → /contact
// app/blog/page.tsx → /blog
// app/dashboard/settings/page.tsx → /dashboard/settings
// app/about/page.tsx
export default function AboutPage() {
return (
<div>
<h1>About Us</h1>
<p>This is the about page of our Next.js application.</p>
</div>
);
}
Dynamic Routes
Square brackets in folder names create dynamic route segments that capture URL parameters. These parameters are passed to the page component as props.
// app/blog/[slug]/page.tsx → /blog/my-first-post
// app/users/[id]/page.tsx → /users/42
// app/blog/[slug]/page.tsx
interface BlogPostProps {
params: Promise<{ slug: string }>;
}
export default async function BlogPost({ params }: BlogPostProps) {
const { slug } = await params;
// Fetch post data based on the slug
const post = await fetch(`https://api.example.com/posts/${slug}`).then(
(r) => r.json()
);
return (
<article>
<h1>{post.title}</h1>
<p>Slug: {slug}</p>
<div dangerouslySetInnerHTML={{ __html: post.content }} />
</article>
);
}
// app/users/[id]/page.tsx
interface UserPageProps {
params: Promise<{ id: string }>;
}
export default async function UserPage({ params }: UserPageProps) {
const { id } = await params;
return <h1>User Profile: {id}</h1>;
}
Catch-All and Optional Catch-All Routes
// Catch-all: app/docs/[...slug]/page.tsx
// Matches: /docs/a, /docs/a/b, /docs/a/b/c
// params.slug = ["a", "b", "c"]
// Optional catch-all: app/docs/[[...slug]]/page.tsx
// Also matches: /docs (slug is undefined)
interface DocsProps {
params: Promise<{ slug?: string[] }>;
}
export default async function DocsPage({ params }: DocsProps) {
const { slug } = await params;
const path = slug ? slug.join("/") : "index";
return <h1>Documentation: {path}</h1>;
}
Navigation
Next.js provides the Link component for client-side navigation and the useRouter hook for programmatic navigation. The Link component prefetches linked pages for instant navigation.
"use client";
import Link from "next/link";
import { useRouter, usePathname } from "next/navigation";
export default function Navigation() {
const router = useRouter();
const pathname = usePathname();
function handleLogout() {
// Clear session and redirect
router.push("/login");
}
return (
<nav>
{/* Declarative navigation */}
<Link href="/" className={pathname === "/" ? "active" : ""}>
Home
</Link>
<Link href="/about">About</Link>
<Link href="/blog">Blog</Link>
{/* Dynamic route link */}
<Link href={`/users/${42}`}>My Profile</Link>
{/* Programmatic navigation */}
<button onClick={() => router.push("/dashboard")}>
Dashboard
</button>
<button onClick={() => router.back()}>Go Back</button>
<button onClick={handleLogout}>Logout</button>
</nav>
);
}
Route Groups
Folders wrapped in parentheses create route groups that organize routes without affecting the URL path. This is useful for applying different layouts to different sections of your app.
// Route groups — parentheses in folder names
// app/(marketing)/about/page.tsx → /about
// app/(marketing)/pricing/page.tsx → /pricing
// app/(app)/dashboard/page.tsx → /dashboard
// app/(app)/settings/page.tsx → /settings
// Each group can have its own layout:
// app/(marketing)/layout.tsx — marketing layout with hero header
// app/(app)/layout.tsx — app layout with sidebar
Tip: Use theLinkcomponent instead of anchor tags for internal navigation.Linkautomatically prefetches the linked page in production, making navigation feel instant. For external links, use regular<a>tags.
Key Takeaways
- File-based routing maps folder/file structure to URL paths automatically.
- Dynamic routes use
[param]folders to capture URL segments as parameters. - Catch-all routes (
[...slug]) match multiple path segments. - Use
Linkfor declarative navigation anduseRouterfor programmatic navigation. - Route groups
(groupName)organize routes and layouts without affecting URLs.