Erro Hydration failed no Next.js

Erro Hydration failed no Next.js

Erro Hydration failed no Next.js: causas reais e solução

Se você está vendo o erro “Erro Hydration failed no Next.js because the initial UI does not match what was rendered on the server” em um projeto Next.js, a boa notícia é: isso é um problema comum e, na maioria dos casos, tem solução simples.

Esse erro acontece quando o HTML gerado no servidor é diferente do HTML gerado no cliente, e o React não consegue “ligar” (hidratar) corretamente os dois.

Neste artigo, você vai entender o que esse erro significa, por que ele acontece e como resolver de forma segura, sem gambiarras.



Resumo rápido (pra quem está com pressa)

👉 O erro Hydration failed acontece quando o conteúdo renderizado no servidor não bate com o que o navegador tenta renderizar depois.
👉 Geralmente é causado por código que depende do navegador, valores dinâmicos ou estado inicial inconsistente.
👉 A solução quase sempre envolve adiar esse código para o client-side ou ajustar a forma como os dados são renderizados.

Agora vamos com calma.


O que significa o erro “Hydration failed” no Next.js?

O Next.js usa Server-Side Rendering (SSR). Isso significa que:

  1. O servidor gera o HTML inicial
  2. Esse HTML é enviado para o navegador
  3. O React “hidrata” esse HTML, tornando-o interativo

O erro aparece quando o React percebe que:

“O HTML que eu renderizei no servidor não é igual ao que estou tentando renderizar no cliente.”

Quando isso acontece, o React não confia no resultado e dispara o erro de hidratação.


Exemplo simples de código que causa o erro

Veja este exemplo:

export default function Page() {
  return <p>{Date.now()}</p>;
}

Por que isso quebra?

  • No servidor, Date.now() gera um valor
  • No cliente, Date.now() gera outro valor
  • O HTML não bate
  • 💥 Erro de hidratação

O mesmo vale para:

  • Math.random()
  • window
  • localStorage
  • document

Causas mais comuns do erro “Hydration failed”

👉 Veja também “Hooks como o useEffect precisam ser usados com cuidado para evitar renderizações inesperadas.”

Código que roda apenas no navegador

Exemplo clássico:

export default function Page() {
  return <p>{window.innerWidth}</p>;
}

No servidor, window não existe.
No cliente, existe.

Resultado: HTML diferente → erro.


Valores dinâmicos renderizados no servidor

Qualquer valor que muda a cada render pode causar problemas:

  • datas
  • números aleatórios
  • dados baseados em horário
  • estados derivados de APIs externas

Se o valor não for previsível, ele não deve ser renderizado no servidor.


Estado inicial inconsistente

👉 Veja também “Esse problema aparece muito em funcionalidades como dark mode.”

Outro erro comum:

const [theme, setTheme] = useState(
  localStorage.getItem("theme")
);

No servidor:

  • localStorage não existe

No cliente:

  • existe e retorna valor

Mais uma vez: HTML diferente.


Como resolver o erro “Hydration failed” no Next.js

Agora a parte importante.


1️⃣ Use useEffect para código client-side

Se algo depende do navegador, execute após a montagem do componente.

import { useEffect, useState } from "react";

export default function Page() {
  const [width, setWidth] = useState(null);

  useEffect(() => {
    setWidth(window.innerWidth);
  }, []);

  return <p>{width}</p>;
}

Assim:

  • servidor renderiza algo previsível
  • cliente ajusta depois
  • hidratação funciona

2️⃣ Verifique se está no navegador

Outra abordagem comum:

if (typeof window === "undefined") {
  return null;
}

Isso evita que o código execute no servidor.

⚠️ Use com cuidado para não esconder conteúdo importante.


3️⃣ Desabilite SSR para componentes específicos

Quando faz sentido, você pode carregar um componente apenas no cliente:

import dynamic from "next/dynamic";

const ClientOnlyComponent = dynamic(
  () => import("./ClientOnlyComponent"),
  { ssr: false }
);

Essa é uma solução limpa para:

  • gráficos
  • bibliotecas que dependem do DOM
  • widgets externos

4️⃣ Ajuste o estado inicial corretamente

Evite depender de valores dinâmicos no useState inicial.

Em vez disso:

const [theme, setTheme] = useState(null);

useEffect(() => {
  setTheme(localStorage.getItem("theme"));
}, []);

Isso mantém o HTML inicial consistente.


Quando você NÃO precisa se preocupar tanto

👉 Veja também “Quando o problema acontece apenas em produção, o backend também pode estar envolvido.”

Nem todo erro de hidratação é o fim do mundo.

Você pode ficar mais tranquilo quando:

  • o erro aparece apenas em desenvolvimento
  • o layout não quebra
  • o comportamento em produção está correto

Mesmo assim, vale corrigir para evitar problemas futuros.


Boas práticas para evitar esse erro no futuro

  • Não renderize valores imprevisíveis no servidor
  • Separe claramente código server e client
  • Use useEffect para efeitos colaterais
  • Evite lógica complexa no render inicial
  • Teste o build de produção antes do deploy

Essas práticas evitam 90% dos erros de hidratação.


Uma dica prática para quem está em produção

Esse erro costuma aparecer:

  • perto do deploy
  • em builds que “sempre funcionaram”
  • depois de pequenas mudanças

Antes de entrar em pânico:

  1. veja qual componente causou o erro
  2. procure por valores dinâmicos
  3. verifique uso de window, document e localStorage

Na maioria das vezes, a correção é simples.


Conclusão

O erro “Hydration failed” no Next.js é assustador à primeira vista, mas quase nunca é um problema grave.

Ele acontece porque:

  • servidor e cliente renderizam coisas diferentes
  • o React percebe isso e avisa

Com pequenos ajustes — geralmente movendo lógica para o client-side — o problema desaparece.

Agora você já sabe onde olhar, o que corrigir e quando se preocupar.

Deixe um comentário

O seu endereço de e-mail não será publicado. Campos obrigatórios são marcados com *