Next.js: next/router
vs next/navigation
Problem Statement
When working with Next.js routing, you'll encounter two similar-looking packages: next/router
and next/navigation
. Both expose a useRouter()
hook, but they behave differently and are not interchangeable. This often causes confusion about when to use each package and why Next.js maintains two separate routing modules. Understanding this distinction is crucial to avoid errors and ensure proper navigation behavior in your application.
Core Difference Explained
next/router
and next/navigation
belong to different Next.js routing paradigms:
Pages Router (next/router
)
- Used exclusively in Next.js applications using the traditional
pages
directory structure - Works with both Client and Server Components
- Provides a full-featured router object with extensive functionality
- Installation:
npm install next@^12
App Router (next/navigation
)
- Designed for Next.js applications using the modern
app
directory (introduced in Next.js 13) - Optimized for Server Components and React Suspense
- Offers a lightweight API with essential navigation capabilities
- Installation:
npm install next@^13
WARNING
Do not mix APIs across routers: Using next/router
in an App Router project will throw:
Error: NextRouter was not mounted. https://nextjs.org/docs/messages/next-router-not-mounted
Practical Usage
Pages Router Implementation
// File location: /pages/about.js
import { useRouter } from 'next/router';
export default function AboutPage() {
const router = useRouter();
// Access query parameters
console.log(router.query.id);
return (
<div>
<h1>About Page</h1>
<button onClick={() => router.push('/contact')}>
Go to Contact
</button>
</div>
);
}
App Router Implementation
// File location: /app/about/page.jsx
'use client'; // Client Component required for hooks
import { useRouter } from 'next/navigation';
export default function AboutPage() {
const router = useRouter();
return (
<div>
<h1>About Page</h1>
<button onClick={() => router.push('/contact')}>
Go to Contact
</button>
</div>
);
}
Key Differences in useRouter()
Behavior
Feature | next/router (Pages) | next/navigation (App) |
---|---|---|
File Structure | pages/ directory | app/ directory |
Server Components | Partial support | Full support |
Route Parameters | router.query object | useParams() hook |
Navigation Methods | push() , replace() | push() , replace() |
Back/Forward Navigation | back() , forward() | No direct equivalent |
Route Change Events | routeChangeStart/Complete | Navigation APIs via suspense |
Migration Guide
When moving from Pages Router to App Router:
Replace imports:
diff- import { useRouter } from 'next/router'; + import { useRouter } from 'next/navigation';
Refactor query access:
Instead ofrouter.query.id
, use:jsx// App Router pattern import { useParams } from 'next/navigation'; function Component() { const params = useParams(); console.log(params.id); }
Replace route detection:
Migrate fromrouter.pathname
to:jsximport { usePathname } from 'next/navigation'; function Component() { const pathname = usePathname(); }
Server redirects:
In Server Components:jsimport { redirect } from 'next/navigation'; async function fetchData() { const res = await fetch('/api/data'); if (!res.ok) redirect('/error'); }
Recommendations
- New projects should use the App Router (
app/
directory +next/navigation
) - Existing Pages Router projects can continue using
next/router
- Avoid mixing approaches within the same project
- Prefer App Router features for:
- Server actions and mutations
- React Suspense integrations
- Streaming server rendering
- Simpler code structure
TIP
When using next/navigation
, navigation occurs through declarative links (<Link>
) or imperative commands (router.push()
). Always import Link
separately:
import Link from 'next/link';
Best Practices Summary
Scenario | Recommendation |
---|---|
Migrating existing Pages app | Maintain next/router |
Building a new project | Use app/ + next/navigation |
Server Components | Use next/navigation for redirects |
Accessing URL parameters | useParams() in App Router |
Navigation events | Suspense APIs in App Router |
Small static sites | Either (consider Pages Router) |
For most modern Next.js development, the App Router and next/navigation
provide better performance, cleaner code organization, and support for React's latest features. Always ensure your imports match your project's router structure to prevent runtime errors.