Enlaces y Navegación
Existen cuatro formas de navegar entre rutas en Next.js:
- Usando el Componente
<Link>
- Usando el hook
useRouter
(Componentes del Cliente) - Usando la función
redirect
(Componentes del Servidor) - Usando la API nativa History
Esta página explicará cómo usar cada una de estas opciones y profundizará en cómo funciona la navegación.
Componente <Link>
<Link>
es un componente integrado que extiende la etiqueta HTML <a>
para proporcionar precarga (prefetching) y navegación del lado del cliente entre rutas. Es la forma principal y recomendada para navegar entre rutas en Next.js.
Puedes usarlo importándolo desde next/link
y pasando una prop href
al componente:
import Link from 'next/link'
export default function Page() {
return <Link href="/dashboard">Dashboard</Link>
}
import Link from 'next/link'
export default function Page() {
return <Link href="/dashboard">Dashboard</Link>
}
Hay otras props opcionales que puedes pasar a <Link>
. Consulta la referencia de API para más información.
Ejemplos
Enlaces a Segmentos Dinámicos
Al enlazar a segmentos dinámicos, puedes usar template literals e interpolación para generar una lista de enlaces. Por ejemplo, para generar una lista de publicaciones de blog:
import Link from 'next/link'
export default function PostList({ posts }) {
return (
<ul>
{posts.map((post) => (
<li key={post.id}>
<Link href={`/blog/${post.slug}`}>{post.title}</Link>
</li>
))}
</ul>
)
}
Verificar Enlaces Activos
Puedes usar usePathname()
para determinar si un enlace está activo. Por ejemplo, para agregar una clase al enlace activo, puedes verificar si el pathname
actual coincide con el href
del enlace:
'use client'
import { usePathname } from 'next/navigation'
import Link from 'next/link'
export function Links() {
const pathname = usePathname()
return (
<nav>
<ul>
<li>
<Link className={`link ${pathname === '/' ? 'active' : ''}`} href="/">
Inicio
</Link>
</li>
<li>
<Link
className={`link ${pathname === '/about' ? 'active' : ''}`}
href="/about"
>
Acerca de
</Link>
</li>
</ul>
</nav>
)
}
'use client'
import { usePathname } from 'next/navigation'
import Link from 'next/link'
export function Links() {
const pathname = usePathname()
return (
<nav>
<ul>
<li>
<Link className={`link ${pathname === '/' ? 'active' : ''}`} href="/">
Inicio
</Link>
</li>
<li>
<Link
className={`link ${pathname === '/about' ? 'active' : ''}`}
href="/about"
>
Acerca de
</Link>
</li>
</ul>
</nav>
)
}
Desplazamiento a un id
El comportamiento predeterminado del App Router de Next.js es desplazarse a la parte superior de una nueva ruta o mantener la posición de desplazamiento para navegación hacia atrás y adelante.
Si deseas desplazarte a un id
específico durante la navegación, puedes agregar un enlace hash #
a tu URL o pasar un enlace hash a la prop href
. Esto es posible porque <Link>
se renderiza como un elemento <a>
.
<Link href="/dashboard#settings">Configuración</Link>
// Salida
<a href="/dashboard#settings">Configuración</a>
Nota importante:
- Next.js se desplazará a la Página si no está visible en el viewport durante la navegación.
Deshabilitar restauración de desplazamiento
El comportamiento predeterminado del App Router de Next.js es desplazarse a la parte superior de una nueva ruta o mantener la posición de desplazamiento para navegación hacia atrás y adelante. Si deseas deshabilitar este comportamiento, puedes pasar scroll={false}
al componente <Link>
, o scroll: false
a router.push()
o router.replace()
.
// next/link
<Link href="/dashboard" scroll={false}>
Dashboard
</Link>
// useRouter
import { useRouter } from 'next/navigation'
const router = useRouter()
router.push('/dashboard', { scroll: false })
Hook useRouter()
El hook useRouter
te permite cambiar rutas programáticamente desde Componentes del Cliente.
'use client'
import { useRouter } from 'next/navigation'
export default function Page() {
const router = useRouter()
return (
<button type="button" onClick={() => router.push('/dashboard')}>
Dashboard
</button>
)
}
Para una lista completa de métodos de useRouter
, consulta la referencia de API.
Recomendación: Usa el componente
<Link>
para navegar entre rutas a menos que tengas un requisito específico para usaruseRouter
.
Función redirect
Para Componentes del Servidor, usa la función redirect
en su lugar.
import { redirect } from 'next/navigation'
async function fetchTeam(id: string) {
const res = await fetch('https://...')
if (!res.ok) return undefined
return res.json()
}
export default async function Profile({ params }: { params: { id: string } }) {
const team = await fetchTeam(params.id)
if (!team) {
redirect('/login')
}
// ...
}
import { redirect } from 'next/navigation'
async function fetchTeam(id) {
const res = await fetch('https://...')
if (!res.ok) return undefined
return res.json()
}
export default async function Profile({ params }) {
const team = await fetchTeam(params.id)
if (!team) {
redirect('/login')
}
// ...
}
Nota importante:
redirect
devuelve un código de estado 307 (Redirección Temporal) por defecto. Cuando se usa en una Acción del Servidor, devuelve un 303 (Ver Otro), que comúnmente se usa para redirigir a una página de éxito como resultado de una solicitud POST.redirect
internamente lanza un error, por lo que debe llamarse fuera de bloquestry/catch
.redirect
puede llamarse en Componentes del Cliente durante el proceso de renderizado pero no en manejadores de eventos. Puedes usar el hookuseRouter
en su lugar.redirect
también acepta URLs absolutas y puede usarse para redirigir a enlaces externos.- Si deseas redirigir antes del proceso de renderizado, usa
next.config.js
o Middleware.
Consulta la referencia de API de redirect
para más información.
Usando la API nativa History
Next.js te permite usar los métodos nativos window.history.pushState
y window.history.replaceState
para actualizar el historial del navegador sin recargar la página.
Las llamadas pushState
y replaceState
se integran con el Router de Next.js, permitiéndote sincronizar con usePathname
y useSearchParams
.
window.history.pushState
Úsalo para agregar una nueva entrada al historial del navegador. El usuario puede navegar de vuelta al estado anterior. Por ejemplo, para ordenar una lista de productos:
'use client'
import { useSearchParams } from 'next/navigation'
export default function SortProducts() {
const searchParams = useSearchParams()
function updateSorting(sortOrder: string) {
const params = new URLSearchParams(searchParams.toString())
params.set('sort', sortOrder)
window.history.pushState(null, '', `?${params.toString()}`)
}
return (
<>
<button onClick={() => updateSorting('asc')}>Ordenar Ascendente</button>
<button onClick={() => updateSorting('desc')}>Ordenar Descendente</button>
</>
)
}
'use client'
import { useSearchParams } from 'next/navigation'
export default function SortProducts() {
const searchParams = useSearchParams()
function updateSorting(sortOrder) {
const params = new URLSearchParams(searchParams.toString())
params.set('sort', sortOrder)
window.history.pushState(null, '', `?${params.toString()}`)
}
return (
<>
<button onClick={() => updateSorting('asc')}>Ordenar Ascendente</button>
<button onClick={() => updateSorting('desc')}>Ordenar Descendente</button>
</>
)
}
window.history.replaceState
Úsalo para reemplazar la entrada actual en el historial del navegador. El usuario no puede navegar de vuelta al estado anterior. Por ejemplo, para cambiar el idioma de la aplicación:
'use client'
import { usePathname } from 'next/navigation'
export function LocaleSwitcher() {
const pathname = usePathname()
function switchLocale(locale: string) {
// ej. '/en/about' o '/fr/contact'
const newPath = `/${locale}${pathname}`
window.history.replaceState(null, '', newPath)
}
return (
<>
<button onClick={() => switchLocale('en')}>Inglés</button>
<button onClick={() => switchLocale('fr')}>Francés</button>
</>
)
}
'use client'
import { usePathname } from 'next/navigation'
export function LocaleSwitcher() {
const pathname = usePathname()
function switchLocale(locale) {
// ej. '/en/about' o '/fr/contact'
const newPath = `/${locale}${pathname}`
window.history.replaceState(null, '', newPath)
}
return (
<>
<button onClick={() => switchLocale('en')}>Inglés</button>
<button onClick={() => switchLocale('fr')}>Francés</button>
</>
)
}
Cómo Funcionan el Enrutamiento y la Navegación
El App Router utiliza un enfoque híbrido para el enrutamiento y la navegación. En el servidor, tu código de aplicación se divide automáticamente por segmentos de ruta (code splitting). Y en el cliente, Next.js precarga (prefetching) y almacena en caché los segmentos de ruta. Esto significa que cuando un usuario navega a una nueva ruta, el navegador no recarga la página, y solo los segmentos de ruta que cambian se vuelven a renderizar, mejorando la experiencia de navegación y el rendimiento.
1. División de Código (Code Splitting)
La división de código te permite dividir el código de tu aplicación en paquetes más pequeños para que el navegador los descargue y ejecute. Esto reduce la cantidad de datos transferidos y el tiempo de ejecución para cada solicitud, lo que mejora el rendimiento.
Componentes del Servidor permiten que tu código de aplicación se divida automáticamente por segmentos de ruta. Esto significa que solo se carga el código necesario para la ruta actual durante la navegación.
2. Precarga (Prefetching)
La precarga es una forma de cargar una ruta en segundo plano antes de que el usuario la visite.
Hay dos formas en que las rutas se precargan en Next.js:
- Componente
<Link>
: Las rutas se precargan automáticamente cuando son visibles en el viewport del usuario. La precarga ocurre cuando la página se carga por primera vez o cuando aparece en la vista al desplazarse. router.prefetch()
: El hookuseRouter
se puede usar para precargar rutas programáticamente.
El comportamiento predeterminado de precarga de <Link>
(es decir, cuando la prop prefetch
no se especifica o se establece en null
) es diferente dependiendo del uso de loading.js
. Solo el diseño compartido, hacia abajo en el "árbol" de componentes renderizados hasta el primer archivo loading.js
, se precarga y almacena en caché durante 30s
. Esto reduce el costo de obtener una ruta dinámica completa y significa que puedes mostrar un estado de carga instantáneo para una mejor retroalimentación visual a los usuarios.
Puedes deshabilitar la precarga estableciendo la prop prefetch
en false
. Alternativamente, puedes precargar los datos completos de la página más allá de los límites de carga estableciendo la prop prefetch
en true
.
Consulta la referencia de API de <Link>
para más información.
Nota importante:
- La precarga no está habilitada en desarrollo, solo en producción.
3. Almacenamiento en Caché (Caching)
Next.js tiene una caché en memoria del lado del cliente llamada Router Cache. A medida que los usuarios navegan por la aplicación, la carga útil del React Server Component de los segmentos de ruta precargados y las rutas visitadas se almacenan en la caché.
Esto significa que durante la navegación, la caché se reutiliza tanto como sea posible, en lugar de hacer una nueva solicitud al servidor, mejorando el rendimiento al reducir el número de solicitudes y la cantidad de datos transferidos.
Aprende más sobre cómo funciona el Router Cache y cómo configurarlo.
4. Renderizado Parcial (Partial Rendering)
El renderizado parcial significa que solo los segmentos de ruta que cambian durante la navegación se vuelven a renderizar en el cliente, y cualquier segmento compartido se preserva.
Por ejemplo, al navegar entre dos rutas hermanas, /dashboard/settings
y /dashboard/analytics
, las páginas settings
y analytics
se renderizarán, y el diseño compartido dashboard
se preservará.

Sin el renderizado parcial, cada navegación causaría que toda la página se vuelva a renderizar en el cliente. Renderizar solo el segmento que cambia reduce la cantidad de datos transferidos y el tiempo de ejecución, lo que mejora el rendimiento.
5. Navegación Suave (Soft Navigation)
Los navegadores realizan una "navegación dura" al navegar entre páginas. El App Router de Next.js habilita una "navegación suave" entre páginas, asegurando que solo los segmentos de ruta que han cambiado se vuelvan a renderizar (renderizado parcial). Esto permite que el estado de React del cliente se preserve durante la navegación.
6. Navegación Atrás y Adelante
Por defecto, Next.js mantendrá la posición de desplazamiento para navegación hacia atrás y adelante, y reutilizará segmentos de ruta en el Router Cache.
7. Enrutamiento entre pages/
y app/
Al migrar incrementalmente de pages/
a app/
, el enrutador de Next.js manejará automáticamente la navegación dura entre los dos. Para detectar transiciones de pages/
a app/
, hay un filtro de enrutador del cliente que utiliza una verificación probabilística de rutas de aplicación, lo que ocasionalmente puede resultar en falsos positivos. Por defecto, tales ocurrencias deberían ser muy raras, ya que configuramos la probabilidad de falsos positivos en un 0.01%. Esta probabilidad se puede personalizar mediante la opción experimental.clientRouterFilterAllowedRate
en next.config.js
. Es importante tener en cuenta que reducir la tasa de falsos positivos aumentará el tamaño del filtro generado en el paquete del cliente.
Alternativamente, si prefieres deshabilitar este manejo por completo y gestionar manualmente el enrutamiento entre pages/
y app/
, puedes establecer experimental.clientRouterFilter
en false en next.config.js
. Cuando esta característica está deshabilitada, cualquier ruta dinámica en páginas que coincida con rutas de aplicación no se navegará correctamente por defecto.