Next.js 16 Middleware en 2026 : Edge Runtime, Authentification et Questions d'Entretien

Maîtrisez le middleware Next.js 16 avec le Edge Runtime, les patterns d'authentification et les questions d'entretien techniques pour développeurs frontend.

Next.js 16 Middleware avec Edge Runtime et authentification

Le middleware Next.js 16 s'exécute avant chaque requête, ce qui en fait la première ligne de défense pour l'authentification, la localisation et la manipulation des requêtes. Comprendre le fonctionnement du middleware est essentiel pour construire des applications de production et constitue un sujet fréquent dans les entretiens techniques frontend.

Le Middleware s'exécute à l'Edge

Le middleware Next.js 16 s'exécute dans l'Edge Runtime par défaut, ce qui signifie qu'il fonctionne dans des centres de données proches des utilisateurs avec des démarrages à froid inférieurs à la milliseconde. C'est idéal pour les vérifications d'authentification et les redirections qui doivent intervenir avant le rendu de la page.

Fonctionnement Interne du Middleware Next.js 16

Le middleware dans Next.js 16 intercepte les requêtes avant qu'elles n'atteignent le gestionnaire de route ou le composant page. Le fichier middleware doit être placé à la racine du projet (à côté de app/ ou pages/) et exporte une fonction par défaut qui reçoit un objet NextRequest.

La contrainte de l'Edge Runtime signifie que le middleware ne peut pas utiliser les API Node.js comme fs ou Buffer. Il s'exécute sur des isolats V8, similaires à Cloudflare Workers, ce qui permet une distribution globale mais limite les API disponibles aux standards Web.

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

export function middleware(request: NextRequest) {
  // Accès aux headers, cookies et URL de la requête
  const token = request.cookies.get('session')?.value
  const pathname = request.nextUrl.pathname

  // Log pour le débogage (visible dans les logs Vercel)
  console.log(`Middleware: ${request.method} ${pathname}`)

  // Continue vers le gestionnaire de route
  return NextResponse.next()
}

// Configure les chemins qui déclenchent le middleware
export const config = {
  matcher: ['/((?!api|_next/static|_next/image|favicon.ico).*)'],
}

La configuration matcher utilise une syntaxe similaire aux regex pour définir quels chemins déclenchent le middleware. Sans cette configuration, le middleware s'exécute sur chaque requête, y compris les assets statiques.

Patterns d'Authentification avec le Middleware Next.js

Le middleware excelle dans la protection des routes qui nécessitent une authentification. Au lieu de vérifier l'authentification dans chaque composant page, une vérification centralisée dans le middleware garantit qu'aucune route protégée ne peut être accédée sans session valide.

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

  // Vérifie si la route nécessite une authentification
  const isProtectedRoute = protectedRoutes.some(route => 
    pathname.startsWith(route)
  )
  const isAuthRoute = authRoutes.some(route => 
    pathname.startsWith(route)
  )

  // Redirige les utilisateurs non authentifiés vers la page de connexion
  if (isProtectedRoute && !token) {
    const loginUrl = new URL('/login', request.url)
    loginUrl.searchParams.set('callbackUrl', pathname)
    return NextResponse.redirect(loginUrl)
  }

  // Redirige les utilisateurs authentifiés hors des pages d'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).*)'],
}

Ce pattern gère à la fois la protection des routes et la prévention des accès aux pages de connexion pour les utilisateurs déjà authentifiés.

Validation JWT dans le Middleware Edge

Valider les tokens JWT à l'edge nécessite des bibliothèques compatibles avec l'Edge Runtime. Le package jose est le choix standard car il utilise les API Web Crypto disponibles dans l'environnement 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) {
    // Efface le cookie invalide et redirige
    const response = NextResponse.redirect(new URL('/login', request.url))
    response.cookies.delete('auth-token')
    return response
  }

  // Ajoute les informations utilisateur aux headers pour les composants serveur
  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 },
  })
}

Transmettre les informations utilisateur via les headers permet aux Server Components d'accéder aux données d'authentification sans requête de base de données supplémentaire.

Gestion de l'Internationalisation dans le Middleware

Le middleware est l'endroit idéal pour gérer la détection de langue et les redirections. Next.js 16 fournit des helpers intégrés pour l'internationalisation qui fonctionnent dans l'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

  // Vérifie si le pathname a déjà une locale
  const pathnameHasLocale = locales.some(
    (locale) => pathname.startsWith(`/${locale}/`) || pathname === `/${locale}`
  )

  if (pathnameHasLocale) return NextResponse.next()

  // Redirige vers le pathname avec la 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 à l'Edge

Implémenter le rate limiting dans le middleware protège les API contre les abus. Les compteurs en mémoire ne fonctionnent pas de manière fiable à l'edge en raison de la nature distribuée, mais des solutions externes comme Upstash Redis fournissent un stockage compatible avec l'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) {
  // Ne limite que les routes 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()
}

Modification des Headers de Réponse

Le middleware peut modifier les headers de réponse pour les politiques de sécurité, la mise en cache et les headers personnalisés. Cela se produit après le traitement de la route mais avant l'envoi de la réponse au client.

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

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

  // Headers de sécurité
  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 personnalisés pour le débogage
  response.headers.set('X-Middleware-Timestamp', Date.now().toString())

  return response
}

Gestion des Erreurs dans le Middleware

Le middleware doit gérer les erreurs de manière gracieuse pour éviter de bloquer les requêtes. Les erreurs non interceptées dans le middleware résultent en une réponse 500, ce qui peut bloquer l'accès à l'ensemble de l'application.

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

export async function middleware(request: NextRequest) {
  try {
    // Opérations du middleware qui peuvent échouer
    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) {
    // Log l'erreur mais ne bloque pas la requête
    console.error('Middleware error:', error)
    
    // Options: continuer, rediriger vers erreur, ou retourner réponse d'erreur
    return NextResponse.next()
  }
}

async function validateSession(token: string): Promise<boolean> {
  // Logique de validation
  return true
}

Prêt à réussir tes entretiens React / Next.js ?

Entraîne-toi avec nos simulateurs interactifs, fiches express et tests techniques.

Questions d'Entretien : Middleware Next.js

Les questions d'entretien sur le middleware testent la compréhension de son modèle d'exécution, ses limitations et ses cas d'utilisation appropriés.

Question : Quelle est la différence entre le middleware et les API Routes pour l'authentification ?

Le middleware s'exécute avant les route handlers et peut intercepter les requêtes vers n'importe quelle route, y compris les pages statiques et les assets. Les API Routes ne s'exécutent que pour les requêtes vers /api/*. Le middleware est idéal pour les vérifications d'authentification à l'échelle de l'application, tandis que les API Routes gèrent la logique métier spécifique.

Question : Pourquoi ne peut-on pas utiliser les API Node.js dans le middleware ?

Le middleware s'exécute dans l'Edge Runtime, qui utilise des isolats V8 au lieu d'un environnement Node.js complet. Cela permet des démarrages à froid inférieurs à la milliseconde et une distribution globale, mais limite les API disponibles aux standards Web (fetch, crypto, etc.).

Question : Comment transmet-on des données du middleware aux Server Components ?

En définissant des headers personnalisés sur la requête en utilisant NextResponse.next({ request: { headers: modifiedHeaders } }). Les Server Components peuvent ensuite lire ces headers en utilisant la fonction headers() de next/headers.

Question : Quelle est l'approche correcte pour la gestion de session dans le middleware ?

Lire les cookies de session et valider les tokens en utilisant des bibliothèques compatibles Edge comme jose pour JWT. Ne pas effectuer de requêtes de base de données directement dans le middleware; utiliser plutôt la validation de tokens ou des API de session externes.

Question : Comment implémenter une chaîne de middlewares dans Next.js ?

Next.js ne supporte qu'un seul fichier middleware, mais on peut chaîner plusieurs fonctions en les composant :

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()
}

Bonnes Pratiques pour le Middleware en Production

Minimiser le travail effectué dans le middleware améliore les temps de réponse. Chaque milliseconde dans le middleware retarde le rendu de la page. Éviter les appels API externes sauf si absolument nécessaire.

Utiliser le matcher de manière appropriée réduit les exécutions inutiles du middleware. Exclure les fichiers statiques, les images et les routes API qui ne nécessitent pas de traitement middleware.

typescript
export const config = {
  matcher: [
    // Correspondance de tous les chemins sauf fichiers statiques
    '/((?!_next/static|_next/image|favicon.ico|public/).*)',
    // Ou liste explicite des routes
    '/dashboard/:path*',
    '/api/protected/:path*',
  ],
}

Les logs dans le middleware doivent être minimaux en production. Chaque console.log ajoute de la latence et consomme des ressources.

Conclusion

Le middleware Next.js 16 fournit une capacité puissante d'interception des requêtes qui s'exécute à l'edge avec des performances minimales. Comprendre ses contraintes (Edge Runtime, pas d'API Node.js) et ses cas d'utilisation appropriés (authentification, i18n, rate limiting) est essentiel pour construire des applications performantes. Les candidats doivent être capables d'expliquer la différence entre middleware et API Routes, de démontrer la gestion des erreurs appropriée et de comprendre comment transmettre des données aux Server Components.

Défi du jour

Tu saurais repérer le bug en React / Next.js ?

Un vrai bout de code, un bug caché, une tentative par jour. Sans compte pour essayer.

Anthony Fillion-Maillet

Écrit par

Anthony Fillion-Maillet

Fondateur de SharpSkill

Développeur fullstack depuis plus de 10 ans. Il dirige SharpSkill et répond de tout ce qui y est publié.

Mis à jour le 20 septembre 2026

Tags

#nextjs
#middleware
#edge-runtime
#authentification
#react

Partager

Articles similaires