Comment résoudre le Hydration Error de Next.js [Guide complet 2026]
Voyez-vous soudainement “Hydration failed because the initial UI does not match what was rendered on the server” ou “Text content does not match server-rendered HTML” lors du développement avec Next.js ? Cet article fournit un guide complet mis à jour pour 2026, couvrant les causes et les solutions concrètes pour les erreurs d’hydratation, y compris l’environnement Next.js 15 le plus récent.
- Qu’est-ce que cette erreur ? Les symptômes que vous verrez
- Pourquoi cette erreur se produit-elle ?
- Solution 1 : Rendu exclusif côté client avec useEffect (Recommandée)
- Solution 2 : Désactiver le SSR avec l’importation dynamique
- Solution 3 : Corriger la structure HTML et gérer les extensions du navigateur (Avancé)
- Comment prévenir les erreurs d’hydratation
- Résumé
- Références
Qu’est-ce que cette erreur ? Les symptômes que vous verrez
Le Hydration Error (erreur d’hydratation) de Next.js se produit lorsqu’il y a une incompatibilité entre le HTML généré par le rendu côté serveur (SSR) et le HTML que React tente de rendre lors du premier rendu côté client.
Qu’est-ce que l’hydratation ?
L’hydratation (Hydration) est le processus par lequel React prend le HTML statique pré-rendu du serveur et y attache des gestionnaires d’événements et un état pour le rendre “interactif” dans le navigateur. On l’appelle “hydratation” parce qu’elle injecte de l’interactivité — comme ajouter de l’eau pour donner vie à quelque chose.
Messages d’erreur courants
Voici les messages d’erreur typiques que les développeurs rencontrent dans la console ou le navigateur :
Hydration failed because the initial UI does not match what was rendered on the server.Text content does not match server-rendered HTML.Error: Hydration failed because the server rendered HTML didn't match the client.Warning: Expected server HTML to contain a matching <div> in <p>.
Quand cela se produit-il ?
Cette erreur apparaît principalement dans les situations suivantes :
- Une erreur rouge apparaît dans la console du navigateur pendant le développement de l’application Next.js
- Des parties d’une page ne s’affichent pas correctement ou les interactions ne fonctionnent pas en production
- Elle est souvent détectée pour la première fois lors de l’aperçu post-build
- Les extensions Chrome qui modifient le DOM peuvent également la déclencher
En termes d’impact, lorsqu’une erreur d’hydratation se produit, React tente de reconstruire complètement le DOM côté client, ce qui peut entraîner une dégradation des performances. De plus, dans Next.js 15 et les versions ultérieures (React 19), les erreurs d’hydratation sont gérées plus strictement — ce qui était auparavant des avertissements peut maintenant être lancé comme des erreurs.
Pourquoi cette erreur se produit-elle ?
Les erreurs d’hydratation ont de nombreuses causes, mais elles peuvent être classées en cinq catégories.
Cause 1 : Utilisation d’API exclusives au navigateur (window, localStorage, navigator)
Comme l’environnement du navigateur n’existe pas côté serveur, référencer directement des objets exclusifs au navigateur comme window, localStorage, navigator ou document dans la logique de rendu produit des résultats différents sur le serveur et le client.
// ❌ MAUVAIS : window n'existe pas sur le serveur, causant une incompatibilité
function MyComponent() {
const width = window.innerWidth; // Erreur ou undefined sur le serveur
return <div>{width > 768 ? 'Bureau' : 'Mobile'}</div>;
}
Un schéma typique est l’utilisation de la branche conditionnelle typeof window !== 'undefined' dans le rendu, qui retourne un JSX différent sur le serveur et le client, provoquant l’erreur.
Cause 2 : Utilisation de dates, heures et valeurs aléatoires
Les fonctions qui retournent des valeurs différentes à chaque appel — comme new Date(), Date.now(), Math.random() et crypto.randomUUID() — produisent des valeurs incompatibles entre le serveur et le client lorsqu’elles sont utilisées pendant le rendu.
// ❌ MAUVAIS : Heures différentes affichées sur le serveur et le client
function Clock() {
return <p>Heure actuelle : {new Date().toLocaleTimeString()}</p>;
}
Les différences de fuseau horaire sont également une cause courante. Lorsque le serveur fonctionne en UTC et que le client est dans un fuseau horaire local, le même objet Date produit des chaînes différentes.
Cause 3 : Imbrication HTML invalide
Lorsque la structure HTML viole les règles d’imbrication (par exemple, placer un <div> à l’intérieur d’une balise <p>), le navigateur corrige automatiquement le HTML, créant une incompatibilité entre le HTML envoyé par le serveur et le DOM interprété par le navigateur.
// ❌ MAUVAIS : <div> ne peut pas aller à l'intérieur de <p>
function BadNesting() {
return (
<p>
Texte
<div>Cette partie est le problème</div>
</p>
);
}
Cause 4 : Extensions Chrome modifiant le DOM
En 2026, l’une des causes les plus frustrantes pour de nombreux développeurs sont les extensions Chrome. Des extensions comme ColorZilla, Grammarly, Google Translate et les gestionnaires de mots de passe ajoutent des attributs ou des éléments au DOM avant que l’hydratation de React ne commence, causant des incompatibilités avec le HTML du serveur.
En particulier dans les environnements Next.js 15 + React 19, les attributs injectés par des extensions comme cz-shortcut-listen="true" ont été signalés comme causes directes d’erreurs d’hydratation.
Cause 5 : Scripts tiers et interférence des widgets
Les scripts tiers comme Google Analytics, les outils de tests A/B, les widgets de chat et les scripts publicitaires peuvent modifier le DOM avant l’hydratation de React, déclenchant des erreurs.
Solution 1 : Rendu exclusif côté client avec useEffect (Recommandée)
La solution la plus recommandée est d’utiliser le hook useEffect pour définir des valeurs uniquement côté client. Comme useEffect s’exécute après la fin de l’hydratation, il maintient la cohérence du HTML entre le serveur et le client.
Étape 1 : Combinaison state et useEffect
Lorsque vous avez besoin de valeurs spécifiques au navigateur (largeur d’écran, valeurs du localStorage, etc.), définissez la valeur initiale pour correspondre au serveur, puis mettez à jour vers des valeurs spécifiques au client dans useEffect.
'use client';
import { useState, useEffect } from 'react';
function ResponsiveComponent() {
// Étape 1 : Définir la valeur initiale identique au serveur
const [isMobile, setIsMobile] = useState(false);
// Étape 2 : Définir la valeur spécifique au client dans useEffect
useEffect(() => {
setIsMobile(window.innerWidth < 768);
const handleResize = () => setIsMobile(window.innerWidth < 768);
window.addEventListener('resize', handleResize);
return () => window.removeEventListener('resize', handleResize);
}, []);
return (
<div>
{isMobile ? <MobileNav /> : <DesktopNav />}
</div>
);
}
Étape 2 : Suivi de l’état de montage
Un modèle plus polyvalent consiste à suivre si le composant a été monté côté client.
'use client';
import { useState, useEffect } from 'react';
function ClientOnlyComponent() {
const [isMounted, setIsMounted] = useState(false);
useEffect(() => {
setIsMounted(true);
}, []);
if (!isMounted) {
return <div className="skeleton">Chargement...</div>;
}
return (
<div>
<p>Heure actuelle : {new Date().toLocaleTimeString()}</p>
<p>Navigateur : {navigator.userAgent}</p>
</div>
);
}
Étape 3 : Créer un Hook personnalisé réutilisable
Nous recommandons de créer un hook personnalisé pour une réutilisation dans tout le projet.
// hooks/useHydration.ts
'use client';
import { useState, useEffect } from 'react';
export function useHydrated() {
const [hydrated, setHydrated] = useState(false);
useEffect(() => {
setHydrated(true);
}, []);
return hydrated;
}
// Utilisation
function MyComponent() {
const hydrated = useHydrated();
if (!hydrated) return <Skeleton />;
return <div>{/* Contenu spécifique au client */}</div>;
}
Notes importantes
- Il est crucial de maintenir la même sortie que le serveur lors du rendu initial de
useEffect - Utilisez une interface skeleton ou des indicateurs de chargement pour minimiser la dégradation de l’expérience utilisateur
- Cette approche peut affecter le SEO, appliquez-la donc avec prudence au contenu que vous souhaitez que les moteurs de recherche indexent
Solution 2 : Désactiver le SSR avec l’importation dynamique
Lorsque le modèle useEffect est peu pratique ou lorsque l’ensemble du composant est exclusivement client, vous pouvez désactiver le SSR en utilisant dynamic() de Next.js.
Utilisation de base
import dynamic from 'next/dynamic';
const ClientOnlyChart = dynamic(
() => import('../components/Chart'),
{
ssr: false,
loading: () => <p>Chargement du graphique...</p>
}
);
export default function Dashboard() {
return (
<div>
<h1>Tableau de bord</h1>
<ClientOnlyChart />
</div>
);
}
Utilisation avec App Router
Avec Next.js 13+ App Router, dynamic fonctionne de la même manière.
// app/dashboard/page.tsx
import dynamic from 'next/dynamic';
const MapComponent = dynamic(
() => import('@/components/Map'),
{ ssr: false }
);
export default function DashboardPage() {
return (
<main>
<h1>Vue de la carte</h1>
<MapComponent />
</main>
);
}
Solution 3 : Corriger la structure HTML et gérer les extensions du navigateur (Avancé)
Corriger les problèmes d’imbrication HTML
// ❌ MAUVAIS : <div> ne peut pas aller dans <p>
<p>Texte<div>Élément de bloc</div></p>
// ✅ BON : Envelopper avec <div> ou utiliser <span>
<div>
<p>Texte</p>
<div>Élément de bloc</div>
</div>
// ✅ BON : Utiliser des éléments en ligne
<p>Texte<span>Élément en ligne</span></p>
Gérer les extensions Chrome
Méthode A : Restreignez l’accès de l’extension au site. Faites un clic droit sur l’icône de l’extension Chrome et changez “Lire et modifier les données du site” en “Lorsque vous cliquez sur l’extension”.
Méthode B : Créez un profil de navigateur dédié au développement sans extensions.
Méthode C : Utilisez suppressHydrationWarning de manière sélective.
// app/layout.tsx
export default function RootLayout({ children }) {
return (
<html lang="fr">
<body suppressHydrationWarning={true}>
{children}
</body>
</html>
);
}
Comment prévenir les erreurs d’hydratation
1. Évitez le code dépendant de l’environnement lors du rendu
N’utilisez pas de code qui génère des valeurs différentes selon l’environnement dans l’instruction return du composant. Déplacez toute la logique dépendante de l’environnement dans useEffect.
2. Utilisez les CSS Media Queries
.mobile-only { display: none; }
.desktop-only { display: block; }
@media (max-width: 768px) {
.mobile-only { display: block; }
.desktop-only { display: none; }
}
3. Automatisez la validation HTML
Utilisez le plugin jsx-a11y d’ESLint et les règles d’eslint-plugin-react pour détecter les imbrications HTML invalides au moment du build.
4. Mettez en place un environnement de test
- Testez régulièrement avec
next build && next start - Testez avec un profil de navigateur propre sans extensions
- Surveillez les erreurs d’hydratation en production avec des outils comme Sentry
5. Optimisez le placement des scripts tiers
import Script from 'next/script';
<Script src="https://example.com/analytics.js" strategy="afterInteractive" />
<Script src="https://example.com/widget.js" strategy="lazyOnload" />
Résumé
Le Hydration Error de Next.js est causé par des incompatibilités entre les résultats de rendu du serveur et du client. Dans l’environnement Next.js 15 + React 19 de 2026, ces vérifications sont plus strictes qu’auparavant, rendant la compréhension et le traitement appropriés de plus en plus importants.
Points clés :
- Le modèle useEffect est la solution la plus efficace pour la plupart des cas
- L’importation dynamique (ssr: false) doit être utilisée lorsque l’ensemble du composant dépend du client
- Veillez toujours à la bonne structure HTML
- Pour les problèmes d’extensions Chrome, utilisez un profil de développement ou
suppressHydrationWarning - Privilégiez les CSS Media Queries plutôt que les branchements conditionnels JavaScript
Références
- Documentation officielle Next.js : Text content does not match server-rendered HTML
- GitHub Discussion : Hydration failed because the initial UI does not match
- GitHub Discussion : Hydration Error caused by chrome extension
- Next.js Hydration Errors in 2026 (Medium)
- Sentry : Fixing Hydration Errors in server-rendered Components
- Resolving hydration mismatch errors in Next.js – LogRocket Blog

コメント