Introducción/Guías/Redirecciones

Cómo manejar redirecciones en Next.js

Existen varias formas de manejar redirecciones en Next.js. Esta página cubrirá cada opción disponible, casos de uso y cómo gestionar un gran número de redirecciones.

APIPropósitoDóndeCódigo de Estado
redirectRedirigir al usuario después de una mutación o eventoComponentes del Servidor, Acciones del Servidor, Manejadores de Ruta307 (Temporal) o 303 (Acción del Servidor)
permanentRedirectRedirigir al usuario después de una mutación o eventoComponentes del Servidor, Acciones del Servidor, Manejadores de Ruta308 (Permanente)
useRouterRealizar una navegación del lado del clienteManejadores de Eventos en Componentes del ClienteN/A
redirects en next.config.jsRedirigir una solicitud entrante basada en una rutaArchivo next.config.js307 (Temporal) o 308 (Permanente)
NextResponse.redirectRedirigir una solicitud entrante basada en una condiciónMiddlewareCualquiera

Función redirect

La función redirect permite redirigir al usuario a otra URL. Puedes llamar a redirect en Componentes del Servidor, Manejadores de Ruta y Acciones del Servidor.

redirect se usa frecuentemente después de una mutación o evento. Por ejemplo, al crear una publicación:

'use server'

import { redirect } from 'next/navigation'
import { revalidatePath } from 'next/cache'

export async function createPost(id: string) {
  try {
    // Llamar a la base de datos
  } catch (error) {
    // Manejar errores
  }

  revalidatePath('/posts') // Actualizar publicaciones en caché
  redirect(`/post/${id}`) // Navegar a la página de la nueva publicación
}

Nota importante:

  • redirect devuelve por defecto un código de estado 307 (Redirección Temporal). Cuando se usa en una Acción del Servidor, devuelve un 303 (Ver Otro), que se usa comúnmente 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 bloques try/catch.
  • redirect puede llamarse en Componentes del Cliente durante el proceso de renderizado pero no en manejadores de eventos. Puedes usar el hook useRouter 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 la API redirect para más información.

Función permanentRedirect

La función permanentRedirect permite redirigir permanentemente al usuario a otra URL. Puedes llamar a permanentRedirect en Componentes del Servidor, Manejadores de Ruta y Acciones del Servidor.

permanentRedirect se usa frecuentemente después de una mutación o evento que cambia la URL canónica de una entidad, como actualizar la URL del perfil de un usuario después de cambiar su nombre de usuario:

'use server'

import { permanentRedirect } from 'next/navigation'
import { revalidateTag } from 'next/cache'

export async function updateUsername(username: string, formData: FormData) {
  try {
    // Llamar a la base de datos
  } catch (error) {
    // Manejar errores
  }

  revalidateTag('username') // Actualizar todas las referencias al nombre de usuario
  permanentRedirect(`/profile/${username}`) // Navegar al nuevo perfil de usuario
}

Nota importante:

  • permanentRedirect devuelve por defecto un código de estado 308 (Redirección Permanente).
  • permanentRedirect 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 la API permanentRedirect para más información.

Hook useRouter()

Si necesitas redirigir dentro de un manejador de eventos en un Componente del Cliente, puedes usar el método push del hook useRouter. Por ejemplo:

'use client'

import { useRouter } from 'next/navigation'

export default function Page() {
  const router = useRouter()

  return (
    <button type="button" onClick={() => router.push('/dashboard')}>
      Panel
    </button>
  )
}

Nota importante:

  • Si no necesitas navegar programáticamente a un usuario, deberías usar un componente <Link>.

Consulta la referencia de la API useRouter para más información.

redirects en next.config.js

La opción redirects en el archivo next.config.js permite redirigir una ruta de solicitud entrante a un destino diferente. Esto es útil cuando cambias la estructura de URLs de las páginas o tienes una lista de redirecciones conocidas de antemano.

redirects soporta coincidencia de rutas, coincidencia de encabezados, cookies y consultas, dándote flexibilidad para redirigir usuarios basado en una solicitud entrante.

Para usar redirects, añade la opción a tu archivo next.config.js:

import type { NextConfig } from 'next'

const nextConfig: NextConfig = {
  async redirects() {
    return [
      // Redirección básica
      {
        source: '/about',
        destination: '/',
        permanent: true,
      },
      // Coincidencia de rutas con comodines
      {
        source: '/blog/:slug',
        destination: '/news/:slug',
        permanent: true,
      },
    ]
  },
}

export default nextConfig

Consulta la referencia de la API redirects para más información.

Nota importante:

  • redirects puede devolver un código de estado 307 (Redirección Temporal) o 308 (Redirección Permanente) con la opción permanent.
  • redirects puede tener un límite en algunas plataformas. Por ejemplo, en Vercel hay un límite de 1,024 redirecciones. Para manejar un gran número de redirecciones (1000+), considera crear una solución personalizada usando Middleware. Consulta manejo de redirecciones a escala para más información.
  • redirects se ejecuta antes que Middleware.

NextResponse.redirect en Middleware

Middleware te permite ejecutar código antes de que se complete una solicitud. Luego, basado en la solicitud entrante, redirigir a una URL diferente usando NextResponse.redirect. Esto es útil si quieres redirigir usuarios basado en una condición (ej. autenticación, gestión de sesiones, etc) o tener un gran número de redirecciones.

Por ejemplo, para redirigir al usuario a una página /login si no está autenticado:

import { NextResponse, NextRequest } from 'next/server'
import { authenticate } from 'auth-provider'

export function middleware(request: NextRequest) {
  const isAuthenticated = authenticate(request)

  // Si el usuario está autenticado, continuar normalmente
  if (isAuthenticated) {
    return NextResponse.next()
  }

  // Redirigir a la página de login si no está autenticado
  return NextResponse.redirect(new URL('/login', request.url))
}

export const config = {
  matcher: '/dashboard/:path*',
}

Nota importante:

  • Middleware se ejecuta después de redirects en next.config.js y antes del renderizado.

Consulta la documentación de Middleware para más información.

Manejo de redirecciones a escala (avanzado)

Para manejar un gran número de redirecciones (1000+), puedes considerar crear una solución personalizada usando Middleware. Esto te permite manejar redirecciones programáticamente sin tener que redeployar tu aplicación.

Para hacer esto, necesitarás considerar:

  1. Crear y almacenar un mapa de redirecciones.
  2. Optimizar el rendimiento de búsqueda de datos.

Ejemplo de Next.js: Consulta nuestro ejemplo de Middleware con filtro Bloom para una implementación de las recomendaciones siguientes.

1. Crear y almacenar un mapa de redirecciones

Un mapa de redirecciones es una lista de redirecciones que puedes almacenar en una base de datos (usualmente un almacén clave-valor) o archivo JSON.

Considera la siguiente estructura de datos:

{
  "/old": {
    "destination": "/new",
    "permanent": true
  },
  "/blog/post-old": {
    "destination": "/blog/post-new",
    "permanent": true
  }
}

En Middleware, puedes leer desde una base de datos como Edge Config de Vercel o Redis, y redirigir al usuario basado en la solicitud entrante:

import { NextResponse, NextRequest } from 'next/server'
import { get } from '@vercel/edge-config'

type RedirectEntry = {
  destination: string
  permanent: boolean
}

export async function middleware(request: NextRequest) {
  const pathname = request.nextUrl.pathname
  const redirectData = await get(pathname)

  if (redirectData && typeof redirectData === 'string') {
    const redirectEntry: RedirectEntry = JSON.parse(redirectData)
    const statusCode = redirectEntry.permanent ? 308 : 307
    return NextResponse.redirect(redirectEntry.destination, statusCode)
  }

  // No se encontró redirección, continuar sin redirigir
  return NextResponse.next()
}

2. Optimización del rendimiento en la búsqueda de datos

Leer un conjunto de datos grande para cada solicitud entrante puede ser lento y costoso. Existen dos formas de optimizar el rendimiento en la búsqueda de datos:

  • Utilizar una base de datos optimizada para lecturas rápidas
  • Usar una estrategia de búsqueda de datos como un filtro Bloom (Bloom filter) para verificar eficientemente si existe una redirección antes de leer el archivo o base de datos de redirecciones más grande.

Considerando el ejemplo anterior, puedes importar un archivo de filtro Bloom generado en el Middleware y luego verificar si la ruta (pathname) de la solicitud entrante existe en el filtro Bloom.

Si existe, reenvía la solicitud a un Manejador de Ruta (Route Handler) que verificará el archivo real y redirigirá al usuario a la URL adecuada. Esto evita importar un archivo grande de redirecciones en el Middleware, lo cual puede ralentizar cada solicitud entrante.

import { NextResponse, NextRequest } from 'next/server'
import { ScalableBloomFilter } from 'bloom-filters'
import GeneratedBloomFilter from './redirects/bloom-filter.json'

type RedirectEntry = {
  destination: string
  permanent: boolean
}

// Inicializar el filtro Bloom desde un archivo JSON generado
const bloomFilter = ScalableBloomFilter.fromJSON(GeneratedBloomFilter as any)

export async function middleware(request: NextRequest) {
  // Obtener la ruta de la solicitud entrante
  const pathname = request.nextUrl.pathname

  // Verificar si la ruta está en el filtro Bloom
  if (bloomFilter.has(pathname)) {
    // Reenviar la ruta al Manejador de Ruta
    const api = new URL(
      `/api/redirects?pathname=${encodeURIComponent(request.nextUrl.pathname)}`,
      request.nextUrl.origin
    )

    try {
      // Obtener datos de redirección del Manejador de Ruta
      const redirectData = await fetch(api)

      if (redirectData.ok) {
        const redirectEntry: RedirectEntry | undefined =
          await redirectData.json()

        if (redirectEntry) {
          // Determinar el código de estado
          const statusCode = redirectEntry.permanent ? 308 : 307

          // Redirigir al destino
          return NextResponse.redirect(redirectEntry.destination, statusCode)
        }
      }
    } catch (error) {
      console.error(error)
    }
  }

  // No se encontró redirección, continuar la solicitud sin redirigir
  return NextResponse.next()
}

Luego, en el Manejador de Ruta (Route Handler):

import { NextRequest, NextResponse } from 'next/server'
import redirects from '@/app/redirects/redirects.json'

type RedirectEntry = {
  destination: string
  permanent: boolean
}

export function GET(request: NextRequest) {
  const pathname = request.nextUrl.searchParams.get('pathname')
  if (!pathname) {
    return new Response('Solicitud incorrecta', { status: 400 })
  }

  // Obtener la entrada de redirección del archivo redirects.json
  const redirect = (redirects as Record<string, RedirectEntry>)[pathname]

  // Manejar falsos positivos del filtro Bloom
  if (!redirect) {
    return new Response('No hay redirección', { status: 400 })
  }

  // Devolver la entrada de redirección
  return NextResponse.json(redirect)
}

Dato útil:

  • Para generar un filtro Bloom, puedes usar una librería como bloom-filters.
  • Debes validar las solicitudes hechas a tu Manejador de Ruta para prevenir solicitudes maliciosas.

On this page