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.

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 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.
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.
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.
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 }
}
}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.
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.
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.
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.
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 :
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.
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.
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.

Écrit par
Anthony Fillion-MailletFondateur 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
Partager
Articles similaires

Questions d'entretien Zustand 2026 : Gestion d'état React et bonnes pratiques
Préparez vos entretiens techniques avec ce guide complet sur Zustand. Découvrez les questions fréquentes, les patterns middleware, la comparaison avec Context API et les meilleures pratiques TypeScript.

React 19 Suspense et Rendu Concurrent : Streaming SSR et Questions d'Entretien 2026
Guide complet sur React 19 Suspense, le rendu concurrent et le Streaming SSR. Découvrez les patterns avancés et préparez-vous aux questions d'entretien technique en 2026.

Tests React en 2026 : Vitest, React Testing Library et Bonnes Pratiques
Maîtriser les tests React avec Vitest et React Testing Library. Découvrir les patterns de test de composants, la gestion asynchrone, les stratégies de mocking et les bonnes pratiques pour les entretiens techniques en 2026.