Redireccionamiento

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

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

Función redirect

La función redirect permite redirigir al usuario a otra URL. Puede 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 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
}
'use server'

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

export async function createPost(id) {
  try {
    // Llamar a 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 retorna un código de estado 307 (Redirección Temporal) por defecto. Cuando se usa en una Acción del Servidor, retorna 303 (Ver Otro), comúnmente usado para redirigir a una página de éxito tras 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 renderizado pero no en manejadores de eventos. Use el hook useRouter en su lugar.
  • redirect también acepta URLs absolutas y puede usarse para redirigir a enlaces externos.
  • Si desea redirigir antes del proceso de renderizado, use next.config.js o Middleware.

Consulte la referencia de API de redirect para más información.

Función permanentRedirect

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

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

'use server'

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

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

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

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

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

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

Nota importante:

  • permanentRedirect retorna un código de estado 308 (Redirección Permanente) por defecto.
  • permanentRedirect también acepta URLs absolutas y puede usarse para redirigir a enlaces externos.
  • Si desea redirigir antes del proceso de renderizado, use next.config.js o Middleware.

Consulte la referencia de API de permanentRedirect para más información.

Hook useRouter()

Si necesita redirigir dentro de un manejador de eventos en un Componente del Cliente, puede 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')}>
      Dashboard
    </button>
  )
}
'use client'

import { useRouter } from 'next/navigation'

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

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

Nota importante:

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

Consulte la referencia de API de 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 cambia la estructura de URL de páginas o tiene una lista de redirecciones conocidas de antemano.

redirects soporta coincidencia de rutas, cabeceras, cookies y consultas, brindando flexibilidad para redirigir usuarios basado en solicitudes entrantes.

Para usar redirects, agregue la opción a su archivo next.config.js:

next.config.js
module.exports = {
  async redirects() {
    return [
      // Redirección básica
      {
        source: '/about',
        destination: '/',
        permanent: true,
      },
      // Coincidencia de ruta con comodín
      {
        source: '/blog/:slug',
        destination: '/news/:slug',
        permanent: true,
      },
    ]
  },
}

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

Nota importante:

  • redirects puede retornar códigos 307 (Redirección Temporal) o 308 (Redirección Permanente) con la opción permanent.
  • redirects puede tener límites en plataformas. Por ejemplo, en Vercel hay un límite de 1,024 redirecciones. Para manejar grandes cantidades (1000+), considere crear una solución personalizada con Middleware. Vea gestión de redirecciones a escala para más.
  • redirects se ejecuta antes que Middleware.

NextResponse.redirect en Middleware

Middleware permite ejecutar código antes de completar una solicitud. Luego, basado en la solicitud entrante, redirigir a otra URL usando NextResponse.redirect. Esto es útil para redirigir usuarios basado en condiciones (ej. autenticación, gestión de sesión) o tener grandes cantidades de redirecciones.

Por ejemplo, para redirigir al usuario a /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 página de login si no está autenticado
  return NextResponse.redirect(new URL('/login', request.url))
}

export const config = {
  matcher: '/dashboard/:path*',
}
import { NextResponse } from 'next/server'
import { authenticate } from 'auth-provider'

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

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

  // Redirigir a 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.

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

Gestión de redirecciones a escala (avanzado)

Para manejar grandes cantidades de redirecciones (1000+), puede considerar crear una solución personalizada con Middleware. Esto permite gestionar redirecciones programáticamente sin necesidad de redeployar su aplicación.

Para esto, necesitará considerar:

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

Ejemplo Next.js: Vea nuestro ejemplo 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 puede almacenar en una base de datos (usualmente clave-valor) o archivo JSON.

Considere la siguiente estructura de datos:

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

En Middleware, puede 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()
}
import { NextResponse } from 'next/server'
import { get } from '@vercel/edge-config'

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

  if (redirectData) {
    const 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, como Vercel Edge Config o Redis.
  • Emplear 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, puede importar un archivo generado de filtro Bloom en el Middleware y luego verificar si la ruta de la solicitud entrante existe en el filtro Bloom.

Si existe, reenvíe la solicitud a un Manejador de Ruta (Route Handler) que verificará el archivo real y redirigirá al usuario a la URL correspondiente. 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 desde el 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 con la solicitud sin redirigir
  return NextResponse.next()
}
import { NextResponse } from 'next/server'
import { ScalableBloomFilter } from 'bloom-filters'
import GeneratedBloomFilter from './redirects/bloom-filter.json'

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

export async function middleware(request) {
  // 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 desde el Manejador de Ruta
      const redirectData = await fetch(api)

      if (redirectData.ok) {
        const redirectEntry = 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 con la solicitud sin redirigir
  return NextResponse.next()
}

Luego, en el Manejador de Ruta:

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 desde el 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)
}
import { NextResponse } from 'next/server'
import redirects from '@/app/redirects/redirects.json'

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

  // Obtener la entrada de redirección desde el archivo redirects.json
  const redirect = redirects[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)
}

Nota importante:

  • Para generar un filtro Bloom, puede usar una biblioteca como bloom-filters.
  • Debe validar las solicitudes hechas a su Manejador de Ruta para prevenir solicitudes maliciosas.