Q&A
How to implement routing in Next.js
Overview
Unlike React Router where you declare routes in code, Next.js derives routes from your folder structure - the file system is the route table. There are two systems: the newer App Router (app/, with React Server Components, layouts, and richer conventions) and the legacy Pages Router (pages/). New projects should use the App Router.
graph TD
A[File-system routing] --> B["App Router: app/ (modern)"]
A --> C["Pages Router: pages/ (legacy)"]
B --> B1["folder/page.tsx → /folder"]
B --> B2["[id]/page.tsx → dynamic /folder/:id"]
B --> B3[layout.tsx → shared nested layouts]
C --> C1["pages/about.tsx → /about"]
style B fill:#1e1b4b,color:#fff
App Router (Next 13+, recommended)
A folder becomes a route segment; a page.tsx inside it makes that segment a navigable page:
app/
page.tsx → /
about/page.tsx → /about
blog/
page.tsx → /blog
[slug]/page.tsx → /blog/:slug (dynamic)
dashboard/
layout.tsx → shared layout for everything under /dashboard
page.tsx → /dashboard
settings/page.tsx → /dashboard/settings
Dynamic segments
Brackets capture URL parameters:
// app/blog/[slug]/page.tsx
export default function Post({ params }: { params: { slug: string } }) {
return <h1>Post: {params.slug}</h1>;
}
Variants: [...slug] (catch-all), [[...slug]] (optional catch-all).
Layouts (nested, persistent)
layout.tsx wraps all pages in its segment and below, persisting across navigation:
// app/dashboard/layout.tsx
export default function DashboardLayout({ children }: { children: React.ReactNode }) {
return <div><nav>Dashboard nav</nav><main>{children}</main></div>;
}
Special files include loading.tsx (Suspense fallback), error.tsx (error boundary), and not-found.tsx.
Pages Router (legacy)
Each file under pages/ is a route:
pages/
index.tsx → /
about.tsx → /about
blog/[slug].tsx → /blog/:slug
// pages/blog/[slug].tsx
import { useRouter } from "next/router";
export default function Post() {
const { slug } = useRouter().query; // dynamic param
return <h1>{slug}</h1>;
}
Navigation
<Link> (client-side, prefetched)
import Link from "next/link";
<Link href="/about">About</Link>
<Link href={`/blog/${slug}`}>Read post</Link>
<Link> does client-side transitions (no full reload) and prefetches in the background for speed.
Programmatic navigation
// App Router
import { useRouter } from "next/navigation";
const router = useRouter();
router.push("/dashboard");
router.back();
// Pages Router
import { useRouter } from "next/router"; // note: different import path
A common gotcha: the App Router imports useRouter from next/navigation, the Pages Router from next/router - they're different.
Reading Route Info (App Router)
import { usePathname, useSearchParams, useParams } from "next/navigation";
const pathname = usePathname(); // "/blog/hello"
const query = useSearchParams(); // ?key=value
const params = useParams(); // { slug: "hello" }
Why This Matters in Interviews
Next.js interviews center on routing. Key points: routing is file-system based (folders/files define routes, no manual config); the App Router uses page.tsx per segment, [param] for dynamic routes, and layout.tsx for nested persistent layouts (plus loading/error/not-found); navigate with <Link> (prefetched client transitions) or useRouter().push. The biggest practical gotcha to mention: App Router vs Pages Router differences, especially useRouter coming from next/navigation vs next/router.
Common Pitfalls
- Importing
useRouterfrom the wrong package (next/navigationfor App Router,next/routerfor Pages). - Forgetting a segment needs a
page.tsxto be routable (a folder alone isn't a route). - Using
<a>instead of<Link>, losing client-side navigation and prefetch. - Mixing App Router and Pages Router conventions in one place.
- Misusing dynamic vs catch-all segment syntax (
[id]vs[...id]).
References
- Next.js App Router routing: https://nextjs.org/docs/app/building-your-application/routing
- Next.js
<Link>: https://nextjs.org/docs/app/api-reference/components/link