Next.js 16 Middleware nel 2026: Edge Runtime, Autenticazione e Domande da Colloquio

Guida completa a Next.js 16 Middleware con Edge Runtime, pattern di autenticazione, URL rewriting e domande tecniche frequenti nei colloqui per sviluppatori frontend.

Next.js 16 Middleware Edge Runtime e Autenticazione

Next.js 16 Middleware viene eseguito prima di ogni richiesta che raggiunge il server, rendendolo la prima linea di difesa per autenticazione, localizzazione e manipolazione delle richieste. Comprendere il middleware è essenziale per costruire applicazioni production-ready ed è un argomento frequente nei colloqui frontend.

Il Middleware gira sull'Edge

Next.js 16 Middleware viene eseguito nell'Edge Runtime di default, il che significa che gira in data center vicini agli utenti con cold start inferiori al millisecondo. Questo lo rende ideale per controlli di autenticazione e redirect che devono avvenire prima del rendering della pagina.

Come Funziona Next.js 16 Middleware Sotto il Cofano

Il middleware in Next.js 16 intercetta le richieste prima che raggiungano il route handler o il componente della pagina. Il file middleware deve essere posizionato nella root del progetto (accanto a app/ o pages/) ed esporta una funzione di default che riceve un oggetto NextRequest.

Il vincolo dell'Edge Runtime significa che il middleware non può utilizzare API Node.js come fs o Buffer. Gira su V8 isolates, simile a Cloudflare Workers, il che abilita la distribuzione globale ma limita le API disponibili agli standard Web.

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

export function middleware(request: NextRequest) {
  // Access request headers, cookies, and URL
  const token = request.cookies.get('session')?.value
  const pathname = request.nextUrl.pathname

  // Log for debugging (visible in Vercel logs)
  console.log(`Middleware: ${request.method} ${pathname}`)

  // Continue to the route handler
  return NextResponse.next()
}

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

La configurazione matcher utilizza una sintassi simile alle regex per definire quali percorsi attivano il middleware. Senza di essa, il middleware viene eseguito su ogni richiesta, inclusi gli asset statici.

Pattern di Autenticazione con Next.js Middleware

Il middleware eccelle nell'autenticazione perché viene eseguito prima di qualsiasi codice della pagina. Un utente senza una sessione valida non vede mai contenuti protetti, nemmeno brevemente. Questo differisce dai controlli di autenticazione lato client che possono mostrare brevemente contenuti protetti prima del redirect.

Il seguente pattern valida un token di sessione e reindirizza gli utenti non autenticati. Si integra con qualsiasi provider di autenticazione che memorizza dati di sessione in cookie o header.

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

const protectedPaths = ['/dashboard', '/settings', '/profile']
const authPaths = ['/login', '/signup']

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

  // Check if path requires authentication
  const isProtectedPath = protectedPaths.some(path => 
    pathname.startsWith(path)
  )
  const isAuthPath = authPaths.some(path => 
    pathname.startsWith(path)
  )

  // Validate session token (call auth service)
  const isValidSession = sessionToken 
    ? await validateSession(sessionToken)
    : false

  // Redirect unauthenticated users to login
  if (isProtectedPath && !isValidSession) {
    const loginUrl = new URL('/login', request.url)
    loginUrl.searchParams.set('callbackUrl', pathname)
    return NextResponse.redirect(loginUrl)
  }

  // Redirect authenticated users away from auth pages
  if (isAuthPath && isValidSession) {
    return NextResponse.redirect(new URL('/dashboard', request.url))
  }

  return NextResponse.next()
}

async function validateSession(token: string): Promise<boolean> {
  // Call auth API endpoint or decode JWT
  // Edge-compatible: use fetch, not Node.js crypto
  try {
    const response = await fetch('https://api.example.com/validate', {
      headers: { Authorization: `Bearer ${token}` },
    })
    return response.ok
  } catch {
    return false
  }
}

Il parametro callbackUrl preserva la destinazione originale, così gli utenti atterrano sulla pagina che avevano inizialmente richiesto dopo il login.

Path Matching e la Configurazione Matcher

La configurazione matcher determina quali richieste attivano il middleware. Errori qui portano a problemi di performance (middleware che gira su ogni asset statico) o falle di sicurezza (percorsi protetti che non attivano i controlli di autenticazione).

Next.js 16 supporta tre sintassi matcher: percorsi stringa, pattern di percorso con parametri e pattern simili a regex con lookahead negativi.

middleware.tstypescript
// Option 1: Simple string paths
export const config = {
  matcher: ['/dashboard/:path*', '/api/:path*'],
}

// Option 2: Exclude static assets with negative lookahead
export const config = {
  matcher: ['/((?!_next/static|_next/image|favicon.ico|public/).*)'],
}

// Option 3: Conditional matching with has/missing
export const config = {
  matcher: [
    {
      source: '/api/:path*',
      has: [{ type: 'header', key: 'Authorization' }],
    },
    {
      source: '/dashboard/:path*',
      missing: [{ type: 'cookie', key: 'session' }],
    },
  ],
}

Le condizioni has e missing nell'opzione 3 aggiungono logica prima ancora che il middleware venga eseguito. Questo è più efficiente che controllare all'interno della funzione middleware.

Pronto a superare i tuoi colloqui su React / Next.js?

Pratica con i nostri simulatori interattivi, flashcards e test tecnici.

Manipolazione di Request e Response nel Middleware

Oltre all'autenticazione, il middleware può modificare le richieste prima che raggiungano i route handler e le risposte prima che raggiungano il client. Casi d'uso comuni includono l'aggiunta di header di sicurezza, URL rewriting per A/B testing e l'iniezione di dati di geolocalizzazione.

La classe NextResponse fornisce metodi per ogni tipo di modifica. I rewrite cambiano la destinazione senza modificare l'URL del browser, mentre i redirect aggiornano entrambi.

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

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

  // Add security headers to all responses
  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'
  )

  // Inject geolocation into request headers for route handlers
  const geo = request.geo
  if (geo?.country) {
    response.headers.set('x-user-country', geo.country)
    response.headers.set('x-user-city', geo.city ?? 'unknown')
  }

  return response
}

I dati di geolocalizzazione (request.geo) vengono popolati dall'Edge Network di Vercel. I deployment self-hosted devono configurare questo tramite il provider di hosting o utilizzare un servizio di geolocalizzazione IP di terze parti.

URL Rewriting per A/B Testing e Feature Flags

I middleware rewrite permettono di servire pagine diverse basate su cookie, header o assegnazione casuale senza che il client lo sappia. Questo pattern alimenta framework di A/B testing e rollout graduali di feature.

Il rewrite avviene sull'edge, quindi entrambe le varianti hanno lo stesso URL e beneficiano dell'edge caching quando appropriato.

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

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

  // Check for existing variant assignment
  let variant = request.cookies.get('ab-variant')?.value

  // Assign variant if not set (50/50 split)
  if (!variant && pathname === '/pricing') {
    variant = Math.random() < 0.5 ? 'control' : 'treatment'
    const response = NextResponse.rewrite(
      new URL(`/pricing/${variant}`, request.url)
    )
    response.cookies.set('ab-variant', variant, {
      maxAge: 60 * 60 * 24 * 30, // 30 days
      httpOnly: true,
    })
    return response
  }

  // Rewrite to assigned variant
  if (variant && pathname === '/pricing') {
    return NextResponse.rewrite(
      new URL(`/pricing/${variant}`, request.url)
    )
  }

  return NextResponse.next()
}

Il cookie persiste l'assegnazione della variante, assicurando che gli utenti vedano la stessa versione nelle visite successive. La scadenza di 30 giorni bilancia la consistenza dell'esperimento con la possibilità di riassegnare utenti a nuovi esperimenti.

Limitazioni dell'Edge Runtime e Workaround

L'Edge Runtime scambia la compatibilità Node.js per distribuzione globale e cold start veloci. Il middleware non può importare moduli specifici di Node.js, il che influenza librerie come bcrypt, jsonwebtoken (quando si usa RS256) e client di database che si affidano a socket TCP.

La documentazione dell'Edge Runtime di Next.js elenca le API supportate. Web Crypto, fetch e la maggior parte delle API Web Platform funzionano. Calcoli pesanti dovrebbero essere spostati in API route che girano in Node.js.

middleware.ts - JWT validation without jsonwebtokentypescript
import { jwtVerify } from 'jose' // Edge-compatible JWT library
import type { NextRequest } from 'next/server'

const JWT_SECRET = new TextEncoder().encode(process.env.JWT_SECRET!)

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

  if (!token) {
    return redirectToLogin(request)
  }

  try {
    // jose library works in Edge Runtime
    const { payload } = await jwtVerify(token, JWT_SECRET)
    
    // Token is valid, check expiration
    if (payload.exp && payload.exp < Date.now() / 1000) {
      return redirectToLogin(request)
    }

    return NextResponse.next()
  } catch {
    // Invalid token signature or format
    return redirectToLogin(request)
  }
}

function redirectToLogin(request: NextRequest) {
  const url = new URL('/login', request.url)
  url.searchParams.set('callbackUrl', request.nextUrl.pathname)
  return NextResponse.redirect(url)
}

La libreria jose fornisce operazioni JWT compatibili con l'Edge. Utilizza Web Crypto sotto il cofano, evitando il modulo crypto di Node.js.

Domande Frequenti su Next.js Middleware nei Colloqui

Gli intervistatori chiedono del middleware per valutare la comprensione del lifecycle delle richieste, dei pattern di sicurezza e dei vincoli dell'Edge computing. Queste domande appaiono in ruoli senior frontend e fullstack che lavorano con Next.js.

Dove viene eseguito il middleware nel lifecycle della richiesta?

Il middleware viene eseguito dopo che la richiesta ha raggiunto il server Next.js ma prima di qualsiasi route matching o rendering della pagina. Su Vercel, viene eseguito sull'Edge, ovvero nel data center più vicino all'utente. Questa posizione lo rende ideale per autenticazione e redirect poiché le richieste non valide non raggiungono mai il server di origine.

Cosa non può fare il middleware rispetto alle API route?

Il middleware gira nell'Edge Runtime, non in Node.js. Non può usare moduli built-in di Node.js (fs, path, crypto con certi algoritmi), client di database basati su TCP o pacchetti npm che dipendono da API Node.js. Calcoli pesanti dovrebbero avvenire in API route o Server Component.

Come si gestisce l'autenticazione nel middleware senza bloccare?

Il pattern prevede la verifica di un cookie di sessione, la sua validazione contro un endpoint di autenticazione o verificando una firma JWT, e il redirect se non valida. Per evitare di bloccare ogni richiesta, si usa la configurazione matcher per eseguire il middleware solo su percorsi protetti. La validazione JWT stateless è più veloce che chiamare un servizio di autenticazione esterno ad ogni richiesta.

Cosa succede se il middleware lancia un errore?

Un errore non gestito nel middleware restituisce una risposta 500 al client. La pagina non viene mai renderizzata. Wrappare la logica del middleware in try-catch e restituire una risposta di fallback (spesso NextResponse.next()) previene fallimenti completi della richiesta. Loggare l'errore prima di continuare aiuta nel debugging.

Per pratica approfondita con questi concetti, il modulo Next.js Middleware e Auth domande da colloquio copre scenari aggiuntivi.

Debug del Middleware in Sviluppo e Produzione

I bug del middleware sono complicati perché il codice gira sull'edge, non nei DevTools del browser. La modalità di sviluppo mostra i log del middleware nel terminale, ma la produzione richiede un'infrastruttura di logging adeguata.

L'approccio seguente logga l'esecuzione del middleware con abbastanza contesto per debuggare problemi senza esporre dati sensibili.

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

export function middleware(request: NextRequest) {
  const start = Date.now()
  const requestId = crypto.randomUUID()

  // Log request start
  console.log(JSON.stringify({
    type: 'middleware_request',
    requestId,
    method: request.method,
    path: request.nextUrl.pathname,
    userAgent: request.headers.get('user-agent')?.slice(0, 100),
    country: request.geo?.country,
  }))

  // Process request
  const response = processRequest(request)

  // Log completion
  console.log(JSON.stringify({
    type: 'middleware_response',
    requestId,
    duration: Date.now() - start,
    status: response.status,
  }))

  // Pass request ID to route handlers
  response.headers.set('x-request-id', requestId)
  return response
}

function processRequest(request: NextRequest): NextResponse {
  // Middleware logic here
  return NextResponse.next()
}

Su Vercel, questi log appaiono nella tab Functions. I deployment self-hosted dovrebbero inviare i log a un servizio come Datadog o usare logging strutturato che la piattaforma di hosting può acquisire.

Best Practice per le Performance del Middleware

Il middleware viene eseguito su ogni richiesta matchata. Una funzione middleware lenta aggiunge latenza ad ogni caricamento di pagina. L'obiettivo è completare l'esecuzione del middleware in meno di 5ms per la maggior parte delle richieste.

  • Minimizzare le operazioni async: Ogni await aggiunge latenza. Cachare i risultati della validazione quando possibile.
  • Usare la configurazione matcher: Escludere asset statici e percorsi pubblici che non necessitano di logica middleware.
  • Evitare chiamate esterne ad ogni richiesta: Validare i JWT localmente invece di chiamare un servizio di autenticazione. Cachare i risultati nei cookie quando appropriato.
  • Mantenere il bundle piccolo: Il middleware ha il suo limite di dimensione del bundle (1MB su Vercel). Importare solo ciò che serve.

La pagina della tecnologia React Next.js su /technologies/react-next copre concetti correlati come Server Component e pattern di data fetching che complementano la conoscenza del middleware.

Inizia a praticare!

Metti alla prova le tue conoscenze con i nostri simulatori di colloquio e test tecnici.

Checklist Next.js 16 Middleware per la Produzione

  • Posizionare il middleware nella root del progetto come middleware.ts, non dentro app/ o pages/
  • Configurare il matcher per escludere _next/static, _next/image e asset pubblici dall'esecuzione del middleware
  • Usare librerie compatibili con l'Edge per la validazione JWT, come jose invece di jsonwebtoken
  • Memorizzare gli URL di callback nei parametri della query quando si reindirizza al login, così gli utenti tornano alla loro destinazione prevista
  • Aggiungere header di sicurezza nel middleware per un'applicazione consistente su tutte le route
  • Loggare l'esecuzione del middleware con request ID per tracciare le richieste attraverso il sistema
  • Mantenere le chiamate API esterne al minimo validando i token localmente e cachando i dati utente in cookie firmati
Sfida del giorno

Sapresti trovare il bug in React / Next.js?

Uno snippet reale, un bug nascosto, un tentativo al giorno. Senza account per provare.

Anthony Fillion-Maillet

Scritto da

Anthony Fillion-Maillet

Fondatore di SharpSkill

Sviluppatore fullstack da oltre 10 anni. Guida SharpSkill e risponde di tutto ciò che vi viene pubblicato.

Aggiornato il 20 settembre 2026

Tag

#nextjs
#middleware
#edge-runtime
#autenticazione
#colloquio

Condividi

Articoli correlati