This error occurs when using the useRouter hook from next/navigation in a Server Component without the "use client" directive. Next.js App Router treats all components as Server Components by default, and hooks can only be used in Client Components.
This error is specific to Next.js 13+ App Router architecture and occurs when you attempt to use the useRouter hook in a Server Component. In the App Router, all components inside the app directory are Server Components by default, which means they render on the server during each request and cannot use React hooks or maintain client-side state. The useRouter hook from next/navigation is a client-side only hook that provides programmatic navigation capabilities like router.push() and router.replace(). When Next.js detects that you're trying to import and use useRouter in a Server Component, it throws this error to prevent runtime failures. This is a fundamental architectural constraint in Next.js 13+. Server Components run only on the server and cannot execute client-side JavaScript, access browser APIs, or use React hooks. To use useRouter, you must explicitly mark your component as a Client Component using the "use client" directive at the top of your file.
Add "use client" as the very first line of your component file, before any imports. This tells Next.js to treat this component as a Client Component where hooks are allowed.
'use client'
import { useRouter } from 'next/navigation'
export default function MyComponent() {
const router = useRouter()
const handleClick = () => {
router.push('/dashboard')
}
return <button onClick={handleClick}>Go to Dashboard</button>
}The "use client" directive must be placed before all imports and code. It's a build-time indicator, not a runtime statement.
Ensure you're importing useRouter from 'next/navigation', not 'next/router'. The App Router uses a different routing system than the Pages Router.
// ✅ Correct - App Router
import { useRouter } from 'next/navigation'
// ❌ Wrong - Pages Router (deprecated in App Router)
import { useRouter } from 'next/router'If you're migrating from the Pages Router, you'll need to update all router imports throughout your codebase. The next/router package is deprecated in Next.js 15+.
If your page or layout needs to remain a Server Component (for data fetching, SEO, etc.), extract the navigation logic into a smaller Client Component.
// app/page.tsx (Server Component)
import NavigationButton from './NavigationButton'
export default async function Page() {
// Server-side data fetching
const data = await fetch('https://api.example.com/data')
return (
<div>
<h1>My Page</h1>
<NavigationButton />
</div>
)
}
// app/NavigationButton.tsx (Client Component)
'use client'
import { useRouter } from 'next/navigation'
export default function NavigationButton() {
const router = useRouter()
return (
<button onClick={() => router.push('/settings')}>
Go to Settings
</button>
)
}This pattern keeps the benefits of Server Components while enabling client-side interactivity where needed.
For most navigation scenarios, the Next.js Link component is preferred over useRouter. Link works in both Server and Client Components without requiring "use client".
// Works in Server Components - no "use client" needed
import Link from 'next/link'
export default function Page() {
return (
<div>
<Link href="/about">Go to About</Link>
<Link href="/contact" replace>Go to Contact (replace history)</Link>
</div>
)
}Only use useRouter when you need programmatic navigation (e.g., after form submission, conditional redirects, or navigation in response to non-click events).
If you need access to URL information in a Server Component, use these alternatives that don't require "use client":
// app/page.tsx (Server Component)
import { headers } from 'next/headers'
export default async function Page({
params,
searchParams
}: {
params: { slug: string }
searchParams: { [key: string]: string | string[] | undefined }
}) {
// Access route parameters directly
console.log('Slug:', params.slug)
// Access search parameters directly
console.log('Query params:', searchParams)
// Access headers if needed
const headersList = headers()
const pathname = headersList.get('x-pathname')
return <div>Server Component with URL data</div>
}For Client Components, use useSearchParams() and useParams() hooks from next/navigation to access URL data.
After making changes, clear the Next.js cache and rebuild to ensure changes take effect:
# Delete Next.js cache
rm -rf .next
# Reinstall dependencies if needed
npm install
# Restart development server
npm run dev
# For production builds
npm run buildSometimes cached build artifacts can cause stale errors even after fixing the code.
If the error persists, search your codebase for all instances of useRouter to find components that might be importing it without "use client":
# Search for useRouter imports
grep -r "useRouter" app/
# Search for next/router imports (should be replaced)
grep -r "from 'next/router'" app/
grep -r "from \"next/router\"" app/Make sure every file that uses useRouter has "use client" at the top and imports from next/navigation.
Server vs Client Component Architecture
Understanding when to use Server vs Client Components is crucial in Next.js App Router:
- Server Components (default): Use for data fetching, accessing backend resources, keeping large dependencies on the server, and improving initial page load performance. They cannot use hooks or browser APIs.
- Client Components: Use for interactivity (onClick, onChange, etc.), React hooks (useState, useEffect, useRouter), browser-only APIs, and custom event listeners.
Migration from Pages Router
If you're migrating from the Pages Router (next/router) to App Router (next/navigation), note these API differences:
- next/router: useRouter() returns { pathname, query, push, replace, ... }
- next/navigation: useRouter() only returns { push, replace, refresh, back, forward, prefetch }
For pathname access, use usePathname(). For query parameters, use useSearchParams(). For route parameters, use useParams().
Performance Considerations
Adding "use client" to a component means that component and all its children will be bundled and sent to the client. To minimize client-side JavaScript:
1. Keep Client Components small and focused (e.g., a navigation button, not an entire page)
2. Import Client Components as low in the tree as possible
3. Pass Server Components as children to Client Components when possible
4. Use the Link component instead of useRouter for most navigation needs
Composition Patterns
You can pass Server Components as children to Client Components:
// ClientComponent.tsx
'use client'
export default function ClientComponent({ children }) {
const router = useRouter()
return <div onClick={() => router.push('/next')}>{children}</div>
}
// page.tsx (Server Component)
import ClientComponent from './ClientComponent'
export default function Page() {
return (
<ClientComponent>
<ServerSideContent /> {/* Remains a Server Component */}
</ClientComponent>
)
}This pattern keeps the benefits of Server Components while enabling client-side interactivity at the boundary.
TypeScript Considerations
The useRouter hook from next/navigation has different TypeScript types than next/router. If you see type errors after updating imports, make sure your @types/react and next dependencies are up to date:
npm install next@latest react@latest react-dom@latest
npm install -D @types/react@latest @types/node@latestCommon Gotchas
- Middleware and Route Handlers run on the server and cannot use useRouter
- The "use client" directive only affects the file it's in and its children, not parent components
- You cannot conditionally add "use client" - it must always be present if the component uses hooks
- Server Actions can be called from Client Components, allowing you to keep most logic server-side
React Hook useCallback has a missing dependency: 'variable'. Either include it or remove the dependency array react-hooks/exhaustive-deps
React Hook useCallback has a missing dependency
Cannot use private fields in class components without TS support
Cannot use private fields in class components without TS support
Cannot destructure property 'xxx' of 'undefined'
Cannot destructure property of undefined when accessing props
useNavigate() may be used only in the context of a <Router> component.
useNavigate() may be used only in the context of a Router component
Cannot find module or its corresponding type declarations
How to fix "Cannot find module or type declarations" in Vite