🔵 App Router – Pages, Layouts & Navigation · Lesson 11
Link, useRouter & Navigation
The <Link> component
To move between pages of your own app, import Link from next/link. It renders a normal <a> tag (good for SEO and accessibility) but adds client-side navigation.
JSX – app/page.jsx
// app/page.jsx
import Link from 'next/link'
export default function Home() {
return (
<nav>
<Link href="/">Home</Link>
<Link href="/courses">Courses</Link>
<Link href="/courses/nextjs">Next.js course</Link>
<Link href="/contact" className="btn">Contact us</Link>
</nav>
)
}Why not a plain <a> tag?
<a href="/courses">
- Full page reload
- Downloads HTML, CSS, JS again
- Layout state is lost
- White flash between pages
<Link href="/courses">
- Only the changed part loads
- Prefetched in the background
- Layout and state stay
- Feels like an app
Active menu with usePathname
A menu should highlight the current page. usePathname() returns the current path. It is a hook, so the component needs 'use client'.
JSX – components/Header.jsx
// components/Header.jsx (from the EduSite project)
'use client'
import Link from 'next/link'
import { usePathname } from 'next/navigation'
const links = [
{ href: '/', label: 'Home' },
{ href: '/courses', label: 'Courses' },
{ href: '/blog', label: 'Blog' },
{ href: '/contact', label: 'Contact' },
]
export default function Header() {
const pathname = usePathname() // e.g. "/courses/nextjs"
const isActive = (href) =>
href === '/' ? pathname === '/' : pathname.startsWith(href)
return (
<nav>
{links.map((l) => (
<Link key={l.href} href={l.href}
className={isActive(l.href) ? 'active' : undefined}>
{l.label}
</Link>
))}
</nav>
)
}Navigate in code: useRouter
Sometimes navigation happens after an action — submitting a search form, finishing a quiz. Use useRouter() from next/navigation.
JSX – app/courses/CourseSearch.jsx
// app/courses/CourseSearch.jsx (from the EduSite project)
'use client'
import { useRouter } from 'next/navigation'
import { useState } from 'react'
export default function CourseSearch({ initial }) {
const router = useRouter()
const [text, setText] = useState(initial)
function onSubmit(e) {
e.preventDefault()
router.push(text ? `/courses?q=${encodeURIComponent(text)}` : '/courses')
}
return (
<form onSubmit={onSubmit}>
<input value={text} onChange={(e) => setText(e.target.value)} />
<button type="submit">Search</button>
</form>
)
}
// Other router methods:
// router.replace('/login') – go without adding a history entry
// router.back() – browser back
// router.refresh() – re-fetch Server Component data for this pageServer redirects: redirect()
JSX – redirect() and config redirects
// app/dashboard/page.jsx (Server Component)
import { redirect } from 'next/navigation'
import { getUser } from '@/lib/auth'
export default async function Dashboard() {
const user = await getUser()
if (!user) redirect('/login') // nothing after this line runs
return <h1>Welcome, {user.name}</h1>
}
// next.config.mjs – permanent redirect for an old URL (SEO safe, 308)
export default {
async redirects() {
return [{ source: '/old-courses', destination: '/courses', permanent: true }]
},
}Links with query strings
JSX
<Link href="/courses?level=beginner">Beginner courses</Link>
// object form – Next.js builds the URL for you
<Link href={{ pathname: '/contact', query: { course: 'nextjs' } }}>
Enquire about Next.js
</Link>
// → /contact?course=nextjsScroll and hash links
JSX
<Link href="/about#team">Our team</Link> {/* jumps to id="team" */}
<Link href="/courses" scroll={false}>Courses</Link> {/* keep scroll position */}
<Link href="/blog" prefetch={false}>Blog</Link> {/* no prefetch */}Common mistakes
- Importing
useRouterfromnext/routerin the App Router → error. Usenext/navigation. - Using hooks (
usePathname) in a Server Component → add'use client'to that component. - Using
<Link>forhttps://other-site.com→ use<a>. - Calling
redirect()inside try/catch → it works by throwing; let it escape the try block.
Summary
<Link>= fast client navigation + prefetch, still a real<a>.usePathname→ active menu;useRouter→ navigate in code.redirect()on the server;redirects()in next.config for old URLs.
✅ Practice
Make a Header with 4 links that highlights the active one. Add a "Go back" button using router.back() on the course page.
Frequently Asked Questions
What is prefetching in Next.js Link?
In production, when a appears in the viewport Next.js downloads the code and data for that route in the background, so the click opens the page almost instantly.
Should I use for external websites?
No. Use a normal for other websites. is for pages inside your own app.
useRouter from next/router or next/navigation?
In the App Router always import from next/navigation. next/router is for the old Pages Router.
Can I redirect inside a Server Component?
Yes. Call redirect('/login') from next/navigation. It stops rendering and sends the user to the new URL.
