Middleware en Next.js 16 en 2026: Edge Runtime, Autenticación y Preguntas de Entrevista

Domina el middleware de Next.js 16 con Edge Runtime, patrones de autenticación y preguntas técnicas de entrevista para desarrolladores frontend.

Middleware de Next.js 16 con Edge Runtime y autenticación

El middleware de Next.js 16 se ejecuta antes de cada solicitud, convirtiéndolo en la primera línea de defensa para autenticación, localización y manipulación de solicitudes. Comprender el funcionamiento del middleware es esencial para construir aplicaciones de producción y constituye un tema frecuente en entrevistas técnicas de frontend.

El Middleware se ejecuta en el Edge

El middleware de Next.js 16 se ejecuta en el Edge Runtime por defecto, lo que significa que funciona en centros de datos cercanos a los usuarios con tiempos de arranque en frío inferiores al milisegundo. Esto lo hace ideal para verificaciones de autenticación y redirecciones que deben ocurrir antes de que la página se renderice.

Cómo Funciona el Middleware de Next.js 16 Internamente

El middleware en Next.js 16 intercepta las solicitudes antes de que lleguen al manejador de ruta o al componente de página. El archivo de middleware debe colocarse en la raíz del proyecto (junto a app/ o pages/) y exporta una función por defecto que recibe un objeto NextRequest.

La restricción del Edge Runtime significa que el middleware no puede utilizar APIs de Node.js como fs o Buffer. Se ejecuta en aislados V8, similar a Cloudflare Workers, lo que permite distribución global pero limita las APIs disponibles a los estándares Web.

middleware.tstypescript
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  // Acceso a headers, cookies y URL de la solicitud
  const token = request.cookies.get('session')?.value
  const pathname = request.nextUrl.pathname

  // Log para depuración (visible en logs de Vercel)
  console.log(`Middleware: ${request.method} ${pathname}`)

  // Continúa hacia el manejador de ruta
  return NextResponse.next()
}

// Configura qué rutas activan el middleware
export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
}

La configuración matcher utiliza una sintaxis similar a regex para definir qué rutas activan el middleware. Sin esta configuración, el middleware se ejecuta en cada solicitud, incluyendo los assets estáticos.

Patrones de Autenticación con Middleware de Next.js

El middleware sobresale en la protección de rutas que requieren autenticación. En lugar de verificar la autenticación en cada componente de página, una verificación centralizada en el middleware garantiza que ninguna ruta protegida pueda ser accedida sin una sesión válida.

middleware.tstypescript
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

const protectedRoutes = ['/dashboard', '/settings', '/profile']
const authRoutes = ['/login', '/register']

export function middleware(request: NextRequest) {
  const token = request.cookies.get('session')?.value
  const pathname = request.nextUrl.pathname

  // Verifica si la ruta requiere autenticación
  const isProtectedRoute = protectedRoutes.some(route => 
    pathname.startsWith(route)
  )
  const isAuthRoute = authRoutes.some(route => 
    pathname.startsWith(route)
  )

  // Redirige usuarios no autenticados a la página de login
  if (isProtectedRoute && !token) {
    const loginUrl = new URL('/login', request.url)
    loginUrl.searchParams.set('callbackUrl', pathname)
    return NextResponse.redirect(loginUrl)
  }

  // Redirige usuarios autenticados fuera de páginas de auth
  if (isAuthRoute && token) {
    return NextResponse.redirect(new URL('/dashboard', request.url))
  }

  return NextResponse.next()
}

export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
}

Este patrón maneja tanto la protección de rutas como la prevención de acceso a páginas de login para usuarios ya autenticados.

Validación JWT en el Middleware Edge

Validar tokens JWT en el edge requiere bibliotecas compatibles con Edge Runtime. El paquete jose es la elección estándar porque utiliza las APIs Web Crypto disponibles en el entorno Edge.

lib/auth-edge.tstypescript
import { jwtVerify } from 'jose'

const JWT_SECRET = new TextEncoder().encode(
  process.env.JWT_SECRET || 'your-secret-key'
)

export async function verifyToken(token: string) {
  try {
    const { payload } = await jwtVerify(token, JWT_SECRET)
    return { valid: true, payload }
  } catch (error) {
    return { valid: false, payload: null }
  }
}
middleware.tstypescript
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import { verifyToken } from './lib/auth-edge'

export async function middleware(request: NextRequest) {
  const token = request.cookies.get('auth-token')?.value

  if (!token) {
    return NextResponse.redirect(new URL('/login', request.url))
  }

  const { valid, payload } = await verifyToken(token)

  if (!valid) {
    // Elimina la cookie inválida y redirige
    const response = NextResponse.redirect(new URL('/login', request.url))
    response.cookies.delete('auth-token')
    return response
  }

  // Agrega información del usuario a los headers para Server Components
  const requestHeaders = new Headers(request.headers)
  requestHeaders.set('x-user-id', payload?.sub as string)
  requestHeaders.set('x-user-role', payload?.role as string)

  return NextResponse.next({
    request: { headers: requestHeaders },
  })
}

Pasar información del usuario a través de headers permite que los Server Components accedan a datos de autenticación sin consultas adicionales a la base de datos.

Manejo de Internacionalización en el Middleware

El middleware es el lugar ideal para manejar la detección de idioma y las redirecciones. Next.js 16 proporciona helpers integrados para internacionalización que funcionan en el Edge Runtime.

middleware.tstypescript
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import { match } from '@formatjs/intl-localematcher'
import Negotiator from 'negotiator'

const locales = ['en', 'fr', 'de', 'es', 'ja']
const defaultLocale = 'en'

function getLocale(request: NextRequest): string {
  const negotiatorHeaders: Record<string, string> = {}
  request.headers.forEach((value, key) => {
    negotiatorHeaders[key] = value
  })

  const languages = new Negotiator({ headers: negotiatorHeaders }).languages()
  return match(languages, locales, defaultLocale)
}

export function middleware(request: NextRequest) {
  const pathname = request.nextUrl.pathname

  // Verifica si el pathname ya tiene un locale
  const pathnameHasLocale = locales.some(
    (locale) => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`
  )

  if (pathnameHasLocale) return NextResponse.next()

  // Redirige al pathname con locale
  const locale = getLocale(request)
  const newUrl = new URL(`/${locale}${pathname}`, request.url)
  
  return NextResponse.redirect(newUrl)
}

export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
}

Rate Limiting en el Edge

Implementar rate limiting en el middleware protege las APIs contra abusos. Los contadores en memoria no funcionan de manera confiable en el edge debido a su naturaleza distribuida, pero soluciones externas como Upstash Redis proporcionan almacenamiento compatible con Edge.

middleware.tstypescript
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'
import { Ratelimit } from '@upstash/ratelimit'
import { Redis } from '@upstash/redis'

const redis = new Redis({
  url: process.env.UPSTASH_REDIS_URL!,
  token: process.env.UPSTASH_REDIS_TOKEN!,
})

const ratelimit = new Ratelimit({
  redis,
  limiter: Ratelimit.slidingWindow(10, '10 s'),
  analytics: true,
})

export async function middleware(request: NextRequest) {
  // Solo limita rutas API
  if (!request.nextUrl.pathname.startsWith('/api')) {
    return NextResponse.next()
  }

  const ip = request.ip ?? '127.0.0.1'
  const { success, limit, reset, remaining } = await ratelimit.limit(ip)

  if (!success) {
    return NextResponse.json(
      { error: 'Too many requests' },
      {
        status: 429,
        headers: {
          'X-RateLimit-Limit': limit.toString(),
          'X-RateLimit-Remaining': remaining.toString(),
          'X-RateLimit-Reset': reset.toString(),
        },
      }
    )
  }

  return NextResponse.next()
}

Modificación de Headers de Respuesta

El middleware puede modificar headers de respuesta para políticas de seguridad, caché y headers personalizados. Esto ocurre después del procesamiento de la ruta pero antes de enviar la respuesta al cliente.

middleware.tstypescript
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export function middleware(request: NextRequest) {
  const response = NextResponse.next()

  // Headers de seguridad
  response.headers.set('X-Frame-Options', 'DENY')
  response.headers.set('X-Content-Type-Options', 'nosniff')
  response.headers.set('Referrer-Policy', 'strict-origin-when-cross-origin')
  response.headers.set(
    'Content-Security-Policy',
    "default-src 'self'; script-src 'self' 'unsafe-inline'"
  )

  // Headers personalizados para depuración
  response.headers.set('X-Middleware-Timestamp', Date.now().toString())

  return response
}

Manejo de Errores en el Middleware

El middleware debe manejar errores de manera elegante para evitar bloquear solicitudes. Los errores no capturados en el middleware resultan en una respuesta 500, lo que puede bloquear el acceso a toda la aplicación.

middleware.tstypescript
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

export async function middleware(request: NextRequest) {
  try {
    // Operaciones del middleware que pueden fallar
    const token = request.cookies.get('session')?.value
    
    if (token) {
      const isValid = await validateSession(token)
      if (!isValid) {
        return NextResponse.redirect(new URL('/login', request.url))
      }
    }

    return NextResponse.next()
  } catch (error) {
    // Registra el error pero no bloquea la solicitud
    console.error('Middleware error:', error)
    
    // Opciones: continuar, redirigir a error, o retornar respuesta de error
    return NextResponse.next()
  }
}

async function validateSession(token: string): Promise<boolean> {
  // Lógica de validación
  return true
}

¿Listo para aprobar tus entrevistas de React / Next.js?

Practica con nuestros simuladores interactivos, flashcards y tests técnicos.

Preguntas de Entrevista: Middleware de Next.js

Las preguntas de entrevista sobre middleware evalúan la comprensión de su modelo de ejecución, limitaciones y casos de uso apropiados.

Pregunta: ¿Cuál es la diferencia entre middleware y API Routes para autenticación?

El middleware se ejecuta antes de los manejadores de ruta y puede interceptar solicitudes a cualquier ruta, incluyendo páginas estáticas y assets. Las API Routes solo se ejecutan para solicitudes a /api/*. El middleware es ideal para verificaciones de autenticación a nivel de toda la aplicación, mientras que las API Routes manejan lógica de negocio específica.

Pregunta: ¿Por qué no se pueden usar APIs de Node.js en el middleware?

El middleware se ejecuta en el Edge Runtime, que utiliza aislados V8 en lugar de un entorno Node.js completo. Esto permite arranques en frío inferiores al milisegundo y distribución global, pero limita las APIs disponibles a los estándares Web (fetch, crypto, etc.).

Pregunta: ¿Cómo se pasan datos del middleware a los Server Components?

Estableciendo headers personalizados en la solicitud usando NextResponse.next({ request: { headers: modifiedHeaders } }). Los Server Components pueden entonces leer estos headers usando la función headers() de next/headers.

Pregunta: ¿Cuál es el enfoque correcto para el manejo de sesiones en el middleware?

Leer cookies de sesión y validar tokens usando bibliotecas compatibles con Edge como jose para JWT. No realizar consultas de base de datos directamente en el middleware; en su lugar, usar validación de tokens o APIs de sesión externas.

Pregunta: ¿Cómo se implementa una cadena de middlewares en Next.js?

Next.js solo soporta un único archivo de middleware, pero se pueden encadenar múltiples funciones componiéndolas:

middleware.tstypescript
import { NextResponse } from 'next/server'
import type { NextRequest } from 'next/server'

type MiddlewareFunction = (
  request: NextRequest
) => Promise<NextResponse | null>

const withAuth: MiddlewareFunction = async (request) => {
  const token = request.cookies.get('session')?.value
  if (!token && request.nextUrl.pathname.startsWith('/dashboard')) {
    return NextResponse.redirect(new URL('/login', request.url))
  }
  return null
}

const withLogging: MiddlewareFunction = async (request) => {
  console.log(`${request.method} ${request.nextUrl.pathname}`)
  return null
}

const middlewares = [withLogging, withAuth]

export async function middleware(request: NextRequest) {
  for (const mw of middlewares) {
    const result = await mw(request)
    if (result) return result
  }
  return NextResponse.next()
}

Mejores Prácticas para Middleware en Producción

Minimizar el trabajo realizado en el middleware mejora los tiempos de respuesta. Cada milisegundo en el middleware retrasa el renderizado de la página. Evitar llamadas a APIs externas a menos que sea absolutamente necesario.

Usar el matcher apropiadamente reduce las ejecuciones innecesarias del middleware. Excluir archivos estáticos, imágenes y rutas API que no requieren procesamiento de middleware.

typescript
export const config = {
  matcher: [
    // Coincide con todos los paths excepto archivos estáticos
    '/((?!_next/static|_next/image|favicon.ico|public/).*)',
    // O lista explícita de rutas
    '/dashboard/:path*',
    '/api/protected/:path*',
  ],
}

Los logs en el middleware deben ser mínimos en producción. Cada console.log agrega latencia y consume recursos.

Conclusión

El middleware de Next.js 16 proporciona una poderosa capacidad de intercepción de solicitudes que se ejecuta en el edge con latencia mínima. Comprender sus restricciones (Edge Runtime, sin APIs de Node.js) y sus casos de uso apropiados (autenticación, i18n, rate limiting) es esencial para construir aplicaciones de alto rendimiento. Los candidatos deben poder explicar la diferencia entre middleware y API Routes, demostrar manejo de errores apropiado y comprender cómo pasar datos a los Server Components.

Reto diario

¿Sabrías detectar el bug en React / Next.js?

Un fragmento real, un bug oculto, un intento al día. Sin cuenta para probar.

Anthony Fillion-Maillet

Escrito por

Anthony Fillion-Maillet

Fundador de SharpSkill

Desarrollador fullstack desde hace más de 10 años. Dirige SharpSkill y responde por todo lo que se publica aquí.

Actualizado el 20 de septiembre de 2026

Etiquetas

#nextjs
#middleware
#edge-runtime
#autenticacion
#react

Compartir

Artículos relacionados