Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/cloudflare/vinext/llms.txt

Use this file to discover all available pages before exploring further.

The next/navigation module provides hooks and utilities for App Router navigation, including pathname/query access, programmatic navigation, and server-side redirects.

Import

import {
  useRouter,
  usePathname,
  useSearchParams,
  useParams,
  useSelectedLayoutSegment,
  useSelectedLayoutSegments,
  redirect,
  permanentRedirect,
  notFound,
  forbidden,
  unauthorized,
  RedirectType,
} from 'next/navigation'

Client Hooks

useRouter

Returns a router instance for programmatic navigation.
'use client'
import { useRouter } from 'next/navigation'

export default function Page() {
  const router = useRouter()
  
  return (
    <button onClick={() => router.push('/dashboard')}>
      Go to Dashboard
    </button>
  )
}

Router Methods

push
(href: string, options?: { scroll?: boolean }) => void
Navigate to a new URL (pushes history entry).
router.push('/about')
router.push('/blog?filter=tech', { scroll: false })
replace
(href: string, options?: { scroll?: boolean }) => void
Navigate to a new URL (replaces history entry).
router.replace('/login')
back
() => void
Navigate to the previous page.
<button onClick={() => router.back()}>Back</button>
forward
() => void
Navigate to the next page (if available).
<button onClick={() => router.forward()}>Forward</button>
refresh
() => void
Re-fetch the current page’s RSC stream (soft refresh).
// After a mutation
router.refresh()
prefetch
(href: string) => void
Manually prefetch a route.
<div onMouseEnter={() => router.prefetch('/dashboard')}>
  Hover to prefetch
</div>

usePathname

Returns the current pathname (without basePath).
'use client'
import { usePathname } from 'next/navigation'

export default function Nav() {
  const pathname = usePathname()
  
  return (
    <nav>
      <a href="/" className={pathname === '/' ? 'active' : ''}>
        Home
      </a>
      <a href="/about" className={pathname === '/about' ? 'active' : ''}>
        About
      </a>
    </nav>
  )
}
pathname
string
Current pathname, e.g., /blog/post-1
  • Excludes basePath (if configured)
  • Excludes query string and hash
  • Updates on navigation

useSearchParams

Returns a URLSearchParams instance for reading query parameters.
'use client'
import { useSearchParams } from 'next/navigation'

export default function SearchResults() {
  const searchParams = useSearchParams()
  const query = searchParams.get('q')
  const page = searchParams.get('page') || '1'
  
  return <div>Search results for: {query} (page {page})</div>
}
searchParams
ReadonlyURLSearchParams
URLSearchParams instance with methods:
  • get(key: string): string | null
  • getAll(key: string): string[]
  • has(key: string): boolean
  • entries(): Iterator<[string, string]>

useParams

Returns dynamic route parameters.
'use client'
// File: app/blog/[slug]/page.tsx
import { useParams } from 'next/navigation'

export default function BlogPost() {
  const params = useParams<{ slug: string }>()
  
  return <h1>Post: {params.slug}</h1>
}
params
Record<string, string | string[]>
Dynamic route parameters, e.g., { slug: 'hello-world' }
  • Single segment: { slug: 'post-1' }
  • Catch-all: { slug: ['2024', '01', 'post'] }

useSelectedLayoutSegment

Returns the active child segment one level below the current layout.
'use client'
// File: app/blog/layout.tsx
import { useSelectedLayoutSegment } from 'next/navigation'

export default function BlogLayout({ children }) {
  const segment = useSelectedLayoutSegment()
  
  return (
    <div>
      <div>Active segment: {segment}</div>
      {children}
    </div>
  )
}
segment
string | null
  • /blognull (no child)
  • /blog/post-1'post-1'
  • /blog/category/tech'category'

useSelectedLayoutSegments

Returns all active segments below the current layout.
'use client'
import { useSelectedLayoutSegments } from 'next/navigation'

export default function Layout({ children }) {
  const segments = useSelectedLayoutSegments()
  
  return (
    <div>
      <div>Path: /{segments.join('/')}</div>
      {children}
    </div>
  )
}
segments
string[]
  • /blog[]
  • /blog/post-1['post-1']
  • /blog/category/tech['category', 'tech']

useServerInsertedHTML

Inject HTML during SSR from client components (CSS-in-JS libraries).
'use client'
import { useServerInsertedHTML } from 'next/navigation'
import { StyleSheetManager } from 'styled-components'

export default function StyledComponentsRegistry({ children }) {
  const [sheet] = useState(() => new ServerStyleSheet())
  
  useServerInsertedHTML(() => {
    const styles = sheet.getStyleElement()
    sheet.instance.clearTag()
    return <>{styles}</>
  })
  
  return (
    <StyleSheetManager sheet={sheet.instance}>
      {children}
    </StyleSheetManager>
  )
}

Server Functions

redirect

Throw a redirect response (caught by the framework).
import { redirect } from 'next/navigation'

export default async function Page() {
  const session = await getSession()
  
  if (!session) {
    redirect('/login')
  }
  
  return <Dashboard />
}
url
string
required
Destination URL (relative or absolute).
type
'push' | 'replace' | RedirectType
default:"'replace'"
Navigation type:
  • 'replace' — 307 redirect (default)
  • 'push' — 307 redirect with history push
  • RedirectType.push / RedirectType.replace

permanentRedirect

Throw a permanent redirect (308).
import { permanentRedirect } from 'next/navigation'

export default async function Page() {
  permanentRedirect('https://example.com')
}
url
string
required
Destination URL.

notFound

Throw a 404 Not Found error.
import { notFound } from 'next/navigation'

export default async function Page({ params }) {
  const post = await getPost(params.id)
  
  if (!post) {
    notFound()
  }
  
  return <Post data={post} />
}
Renders the nearest not-found.tsx file.

forbidden

Throw a 403 Forbidden error (Next.js 16+).
import { forbidden } from 'next/navigation'

export default async function AdminPage() {
  const user = await getUser()
  
  if (!user.isAdmin) {
    forbidden()
  }
  
  return <AdminPanel />
}
Renders the nearest forbidden.tsx file (or error.tsx as fallback).

unauthorized

Throw a 401 Unauthorized error (Next.js 16+).
import { unauthorized } from 'next/navigation'

export default async function ProfilePage() {
  const session = await getSession()
  
  if (!session) {
    unauthorized()
  }
  
  return <Profile user={session.user} />
}
Renders the nearest unauthorized.tsx file (or error.tsx as fallback).

Shallow Routing

Update the URL without re-fetching data:
'use client'
import { useRouter, usePathname, useSearchParams } from 'next/navigation'

export default function Filters() {
  const router = useRouter()
  const pathname = usePathname()
  const searchParams = useSearchParams()
  
  function setFilter(filter: string) {
    const params = new URLSearchParams(searchParams)
    params.set('filter', filter)
    router.push(pathname + '?' + params.toString())
  }
  
  return (
    <button onClick={() => setFilter('tech')}>
      Tech Posts
    </button>
  )
}
Next.js 15+ automatically intercepts history.pushState() / replaceState() calls, so direct manipulation works:
// Also works
window.history.pushState(null, '', '?filter=tech')

Prefetching

<Link> components automatically prefetch on viewport entry (250px margin).

Manual (useRouter)

function Card({ href }) {
  const router = useRouter()
  
  return (
    <div onMouseEnter={() => router.prefetch(href)}>
      <a href={href}>Read more</a>
    </div>
  )
}

Cache TTL

Prefetched entries are valid for 30 seconds. Stale entries are re-prefetched on next trigger.

basePath Support

All navigation functions automatically handle basePath:
// next.config.js
module.exports = { basePath: '/docs' }
router.push('/api')  // Navigates to /docs/api
usePathname()        // Returns /api (without basePath)

i18n Support

Use the locale parameter for internationalized routing:
import Link from 'next/link'

<Link href="/" locale="fr">Français</Link>
<Link href="/" locale={false}>Default Locale</Link>

Limitations

SSR hook usage: Client hooks (useRouter, usePathname, etc.) cannot be called during SSR of client components. Use them inside useEffect or event handlers.
Concurrent navigation: Multiple rapid router.push() calls may result in race conditions. Await navigation if order matters.

Source

View source code → Implementation: /home/daytona/workspace/source/packages/vinext/src/shims/navigation.ts