Hydration mismatch no Next.js: causas e soluções
Índice
ToggleO hydration mismatch no Next.js acontece quando o HTML entregue pelo servidor não corresponde ao resultado que o navegador tenta montar ao carregar a página. O React detecta essa diferença, tenta corrigir o conteúdo e, em desenvolvimento, mostra um aviso no console. Em produção, o problema pode aparecer como conteúdo que troca de lugar,layout quebrado, valores duplicados ou interações inesperadas.
A boa notícia é que esse erro costuma ter uma causa identificável. Ele pode estar ligado à data e à hora, ao idioma do navegador, ao armazenamento local, a dados que chegam depois da renderização ou até a uma biblioteca que gera valores diferentes no servidor e no cliente.
Entender o processo de hidratação é importante porque a mensagem do console costuma apontar o componente, mas não explica toda a causa. Neste guia, você verá como investigar o erro, quais são as soluções mais comuns e como evitar que o problema volte a aparecer em futuras alterações.
Este conteúdo tem caráter informativo. Decisões técnicas devem ser tomadas com profissional especializado.
O que é hydration mismatch no Next.js

O Next.js usa o React para renderizar uma aplicação no servidor e continuar a renderização no navegador. O servidor entrega uma versão inicial do HTML, o que ajuda no carregamento e naindexação por mecanismos de busca. Depois que a página é aberta, o React executa a hidratação, processo em que o navegador associa essa estrutura inicial aos componentes JavaScript.
Durante a hidratação, o React espera que o componente produza exatamente o mesmo resultado no cliente. Se o servidor renderizou uma informação e o navegador calcula outra, surge o hydration mismatch.
Um exemplo simples seria um componente que exibe o dia atual:
function DataAtual() {
const data = new Date().toLocaleDateString('pt-BR')
return <p>Data: {data}</p>
}
O servidor pode gerar a data em 7 de novembro. Pouco depois, o navegador gera essa mesma informação em outro momento. Se a data também depende do fuso horário ou do idioma do dispositivo, a diferença fica ainda mais evidente. O HTML inicial e a segunda renderização não são iguais.
A mensagem do console costuma usar expressões como "Text content did not match" ou "Hydration failed because the initial UI does not match what was rendered on the server". O aviso é importante porque a aplicação está tentando reconciliar duas versões do mesmo conteúdo.
Por que o React precisa dessa correspondência?
A hidratação permite que uma aplicaçãocontinue interativa depois de o HTML inicial ser exibido. Para isso, o React precisa conectar eventos, estados e atualizações aos elementos que já estão na tela.
Se a estrutura mudar no primeiro carregamento, podem surgir efeitos colaterais. O React pode descartar a árvore renderizada no servidor e reconstruir a árvore no navegador. Isso consome recursos e pode bagunçar elementos que já estavam sendo usados.
O objetivo da hidratação não é apenas evitar um aviso no console. Ela mantém a continuidade visual entre o servidor e o cliente.
Hydration mismatch é o mesmo que erro em produção?
Não necessariamente. O comportamento depende do ambiente e do tipo de incompatibilidade.
Em desenvolvimento, o React costuma mostrar detalhes adicionais, como o componente afetado e uma entre o HTML do servidor e o resultado do cliente. Em produção, o aviso pode ser omitido ou abreviado, mas os efeitos da renderização ainda podem aparecer.
A auditoria do React no navegador pode encontrar erros mesmo quando o terminal não apresenta uma mensagem clara. Por isso, um console aparentemente silencioso não prova que a aplicação está livre de hydration mismatch.
Causas comuns do hydration mismatch no Next.js

As causas mais frequentes vêm de valores que dependem do navegador, de dados assíncronos ou de APIs que não funcionam igual nos dois ambientes.
Data, hora e fuso horário
Data e hora são parmi as causas mais comuns. O servidor pode estar em UTC, enquanto o navegador usa o fuso horário da pessoa visitante. O idioma também influencia a formatação.
Evite chamar new Date() diretamente durante a renderização de componentes que devem ser idênticos nos dois ambientes. Renderize a informação no cliente dentro de um useEffect, use uma biblioteca de formatação que receba o fuso horário de forma explícita ou adote uma estratégia de renderização diferente.
A renderização do cliente após a hidratação pode ser feita assim:
'use client'
import { useEffect, useState } from 'react'
export function DataAtual() {
const [data, setData] = useState<string | null>(null)
useEffect(() => {
setData(new Date().toLocaleDateString('pt-BR'))
}, [])
return <p>Data: {data ?? 'Carregando...'}</p>
}
O valor inicial é o mesmo no servidor e no cliente. Depois da montagem, o estado é atualizado no navegador.
Idioma, moeda e formatação regional
O idioma do navegador pode diferir do idioma configurado no servidor. toLocaleDateString(), toLocaleString() e Intl.NumberFormat() podem produzir resultados diferentes conforme as configurações regionais.
Para evitar essa diferença, informe o idioma explicitamente e padronize o fuso horário quando ele fizer sentido para o produto. Se a experiência precisa respeitar a preferência do visitante, renderize uma estrutura neutra durante a hidratação e aplique a preferência local depois.
Randomização e valores gerados em tempo de execução
Chamadas como Math.random() produzem números diferentes a cada execução. O mesmo acontece com identificadores gerados no navegador. Se esses valores forem renderizados imediatamente, o servidor e o cliente podem discordar.
Para evitar essa diferença, informe o idioma explicitamente e padronize o fuso horário quando ele fizer sentido para o produto. Se a experiência precisa respeitar a preferência do visitante, renderize uma estrutura neutra durante a hidratação e aplique a preferência local depois.
Randomização e valores gerados em tempo de execução
Chamadas como Math.random() produzem números diferentes a cada execução. O mesmo acontece com identificadores gerados no navegador. Se esses valores forem renderizados imediatamente, o servidor e o cliente podem discordar.
Em vez de sortear durante a renderização, o ideal é fazer o sorteio após a hidratação ouutilizar um identificador estável fornecido pelo servidor. Componentes que dependem de useId() do React normalmente recebem uma solução de identificadores SSR, mas bibliotecas externas podem não seguir esse padrão.
Dados do navegador
window, localStorage, sessionStorage, navigator e document não existem durante a renderização no servidor. Acessá-los no corpo do componente pode gerar erro ou_difference na resultado.
A regra prática é simples: leia esses dados dentro de useEffect ou em uma função marcada para rodar apenas no cliente. O estado inicial deve ter um valor seguro e previsível.
'use client'
import { useEffect, useState } from 'react'
export function Saudacao() {
const [nome, setNome] = useState('visitante')
useEffect(() => {
const nomeSalvo = localStorage.getItem('nome')
if (nomeSalvo) setNome(nomeSalvo)
}, [])
return <p>Olá, {nome}</p>
}
Estado controlado por extensões do navegador
Extensões podem injetar ou modificar elementos da página. Assim, o conteúdo observado pelo navegador pode ser diferente do HTML original. Também há casos em que scripts de terceiros alteram a estrutura do DOM antes da hidratação.
Quando o erro aparece apenas em determinado navegador, vale testar em uma janela anônima, desativar extensões e comparar o resultado. A causa pode estar fora do código da aplicação.
Bibliotecas de interface e animações
Algumas bibliotecas dependem de APIs do navegador, medem a largura da janela, usam valores aleatórios ou executam verificações de recursos disponíveis. Se a renderização inicial ocorre no servidor, mas a biblioteca já assume que existe um window, o resultado pode divergir.
Verifique a documentação da biblioteca e os erros de console. Bibliotecas usadas em toda a interface podem precisar de carregamento dinâmico, ambientessó de cliente ou uma condição que evite a renderização incompatível no servidor.
Busca de parâmetros sem tratamento adequado
Código que lê window.location.search durante a renderização também pode gerar outro valor no cliente. Se a URL puder mudar sem recarregar a página, prefira mechanisms de roteamento e dados fornecidos pelo App Router.
Como identificar a origem do hydration mismatch

O primeiro passo é reproduzir o erro em um ambiente controlado. A mensagem do console pode ficar mais clara quando o projeto roda em desenvolvimento, sem minificação e com o React em modo de desenvolvimento.
Leia o stack trace do componente
A mensagem indica o caminho do componente afetado. Abra esse arquivo e procure por valores derivados de Date, Math.random(), window, navigator, localStorage, Intl ou estado inicial.
No Next.js, a origem pode aparecer tanto no terminal quanto no console do navegador. Em alguns casos, o erro é shown no console do navegador, enquanto o terminal exibe apenas o componente relacionada à exceção.
Compare o HTML do servidor com o resultado do cliente
O React costuma exibir uma diferença. Mesmo que a mensagem seja resumida, ela normalmente aponta elementos como p, span, div ou text. O conteúdo anterior e o conteúdo esperado ajudam a identificar qual dado está mudando.
Você também pode abrir a página com JavaScript desabilitado para visualizar o HTML inicial. Depois, compare esse resultado com a página depois que o React termina a hidratação.
Verifique a ordem dos hooks
A ordem dos hooks, como useState e useEffect, precisa permanecer igual entre renderizações. Condicionar a chamada de um hook dentro de outra condição pode provocar erros diferentes de hydration mismatch, mas costuma aparecer como erro de hooks.
Confira também se o componente retorna de forma condicional antes de todos os hooks serem executados. O React exige que a ordem seja previsível.
Teste sem extensões e scripts de terceiros
Se o aviso só ocorre em um navegador específico, desative as extensões. Depois, recarregue a página em uma sessão anônima e em outro navegador. Se o erro desaparecer, o problema pode estar em uma extensão, em um bloqueador ou em uma integração externa.
Reproduza o problema no Build de produção
O ambiente de desenvolvimento pode expor detalhes que ficam ocultos após a compilação. Execute o build e a inicialização de produção antes de considerar o problema resolvido.
npm run build
npm run start
Use os comandos disponíveis no seu projeto. Teste a rota afetada, navegue entre páginas e recarregue o navegador. Um hydration mismatch pode ocorrer apenas em produção por causa de otimizações, minificação ou comportamento de bibliotecas externas.
Soluções práticas para evitar hydration mismatch

A solução depende da origem. Alterar um componente sem entender por que ele diverge no navegador pode esconder o sintoma e deixar a causa original intacta.
Mantenha o primeiro render igual no servidor e no cliente
O primeiro render deve ser previsível. Use valores estáticos, props recebidas do servidor ou estados iniciais que não dependam do navegador.
Evite este padrão em um componente renderizado no servidor:
const preferencia = window.localStorage.getItem('tema')
A leitura de window durante a renderização não funciona no servidor. O código deve começar com um estado neutro e carregar a preferência depois.
Renderize dados dependentes do navegador após a hidratação
useEffect é executado depois que o componente é montado no cliente. Ele funciona bem para valores locais, como tema, idioma, preferências e medições disponíveis no navegador.
A desvantagem é que o conteúdo pode aparecer após a hydration. Para evitar saltos visuais, use um esqueleto de carregamento com a mesma altura do conteúdo final.
Use useSyncExternalStore para estado externo
O hook useSyncExternalStore do React é útil quando o estado vem de uma fonte externa, como armazenamento local ou uma API do navegador. Ele permite informar o snapshot usado no servidor e o snapshot observado no cliente.
'use client'
import { useSyncExternalStore } from 'react'
function subscribe(callback: () => void) {
window.addEventListener('storage', callback)
return () => window.removeEventListener('storage', callback)
}
function getSnapshot() {
return localStorage.getItem('tema') ?? 'claro'
}
function getServerSnapshot() {
return 'claro'
}
export function Tema() {
const tema = useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot)
return <p>Tema: {tema}</p>
}
Esse padrão exige que o snapshot do servidor seja compatível com a renderização inicial. Ele não deve ser usado para ocultar dados aleatórios sem uma regra estável.
Controle a renderização de componentes do cliente
O Next.js permite carregar um componente apenas no navegador por meio de uma importação dinâmica com ssr: false. A opção é útil para componentes que dependem de APIs do DOM, mas deve ser usada com cuidado.
import dynamic from 'next/dynamic'
const PainelDoNavegador = dynamic(
() => import('./PainelDoNavegador'),
{ ssr: false },
)
Componentes carregados dessa forma não produzem HTML inicial no servidor. Isso evita a incompatibilidade, mas também altera a estratégia de renderização e pode afetar carregamento, indexação e experiência de uso. Em versões recentes do Next.js, essa opção não é permitida em Server Components nos cenários em que a aplicação é compilada com o React Server Components.
Proteja o renderização apenas quando necessário
Pode ser tentador colocar todo o componente em 'use client', mas isso apenas move a decisão para o navegador. O arquivo continua hydration e precisa ser examinado.
No App Router, a diretiva deve ficar no topo do arquivo. A prática é manter a maior parte da interface no servidor e tornar cliente apenas os componentes que precisam de estado, eventos ou APIs do navegador.
Padronize a serialização de dados
Props pasadas de um Server Component para um Client Component são serializadas. Valores como Date, funções e classes podem perder informação ou não ser serializáveis. O Next.js usa o protocolo Flight para transportar essa comunicação.
Se um componente precisa de uma data, envie uma string ISO ou um timestamp. Evite passar objetos com métodos e funções entre componentes com fronteiras diferentes.
Cuide da ordem de carregamento dos scripts
Scripts que modificam o DOM podem hydration. Em geral, não é necessário manipular a árvore renderizada pelo React para corrigir um hydration mismatch. A solução mais segura é remover a manipulação desnecessária ou fazer a integração por um componente React.
Hydration mismatch em diferentes modos de renderização
O Next.js trabalha com diferentes estratégias de renderização. Entender qual parte é renderizada no servidor ajuda a separar problema de dados, problema de Client Component e integração inadequada entre APIs.
| Modo | Onde o HTML inicial é gerado | Onde a interação é habilitada | Atenção principal |
|---|---|---|---|
| Server Components | No servidor | Depende dos componentes importados | Evite APIs do navegador no corpo do componente |
| — | — | — | — |
| Client Components | No servidor e no cliente | No cliente | O primeiro render precisa ser igual nos dois ambientes |
| Renderização estática | No build ou na requisição, conforme a rota | No cliente | Parâmetros e cookies podem exigir estratégia |
Server Components
Server Components são renderizados no servidor e podem entregar dados já processados para Client Components. Eles são úteis para buscar conteúdo, consultar bancos e reduzir o código enviado ao navegador.
A grande vantagem é que o resultado pode ser serializado e enviado de forma previsível. O ponto de atenção está na fronteira: quando um Server Component passa props para um Client Component, os dados precisam ser serializáveis.
Client Components
Client Components são renderizados no servidor para gerar o HTML inicial e depois hidratados no navegador. É nesse tipo de componente que aparecem interações como onClick, hooks de estado e acesso a window.
O componente precisa de um valor inicial coerente. Se o valor depende de uma preferência local, a atualização deve ocorrer depois da hidratação.
Rotas estáticas e dinâmicas
Uma rota estática pode ser gerada no build. Uma rota dinâmica pode ser gerada no servidor durante a requisição. O App Router permite combinar as duas estratégias.
Se o conteúdo depende de cookies, cabeçalhos ou autenticação, ele normalmente precisa ser renderizado dinamicamente. Fixar a rota como estática pode levar a comportamento inesperado, embora isso seja diferente de hydration mismatch.
Streaming com Suspense
O streaming envia partes da página ao navegador conforme ficam prontas. Com o React 18 e recursos do App Router, essa estratégia melhora a perceived performance.
O conteúdo inicial ainda precisa ser consistente. Se um componente que altera o DOM ao carregar receber dados em momentos diferentes, podem surgir diferenças de estado. Use estados de carregamento explícitos e evite esconder conteúdo com scripts que compete com a hidratação.
Checklist para revisar sua aplicação
Uma revisão método costuma revelar a origem mais rápido do que modificar vários componentes ao mesmo tempo.
- Procure por
new Date(),Date.now(),Math.random()e funções que retornam valores aleatórios dentro de componentes renderizados. - Verifique acessos a
window,document,navigator,localStorageesessionStorageno corpo do componente. - Confirme se formatação de data, número e moeda usa idioma e fuso horário explícitos.
- Leia os avisos do console na ordem em que aparecem, pois um erro inicial pode esconder o erro real.
- Verifique extensões, bloqueadores e scripts de terceiros no navegador.
- Compare o resultado em desenvolvimento e no build de produção.
- Revise a serialização das props entre Server Components e Client Components.
- Confirme que o esqueleto de carregamento tem dimensões compatíveis com o conteúdo final.
O que fazer quando o erro aponta para um componente compartilhado
Componentes compartilhados podem receber dados de várias rotas. Verifique se algum chamador envia uma prop que muda entre o servidor e o cliente.
Adicione logs apenas no ambiente apropriado e remova os logs depois. Evite imprimir objetos inteiros no console, pois o resultado pode ficar grande e esconder a informação útil. Prefira registrar o nome do campo e o tipo de dado esperado.
Quando o problema aparece somente em uma rota
A rota pode estar usando um recurso diferente das demais. Procure por chamadas a APIs do navegador, bibliotecas de gráficos, mapas ou animações dentro da árvore dessa página.
Quando o problema aparece em todas as páginas
Nesse caso, Layout, providers e componentes globais. Verifique o cabeçalho, o rodapé, temas, scripts de analytics e wrappers que cercam toda a aplicação.
Quando o problema começa após uma integração
Revise as versões da biblioteca e o momento em que ela é importada. Uma atualização pode ter alterado o comportamento entre servidor e cliente. Compare a documentação da versão instalada com a documentação mais recente.
Cuidados com SEO, acessibilidade e desempenho
Corrigir hydration mismatch não deve ser tratado como um simples ajuste visual. A renderização consistente também ajuda mecanismos de busca, leitores de tela e pessoas que navegam por teclado.
Conteúdo inicial consistente
Quando o HTML inicial é igual ao resultado do cliente, a página não precisa trocar de texto ou de layout logo após o carregamento. Isso reduz o risco de cliques em elementos que mudam de posição e melhora a percepção de estabilidade.
Estados de carregamento compreensíveis
Se o dado depende do navegador, exiba um estado inicial coerente. Esqueletos de carregamento devem indicar que a informação está sendo preparada, sem prometer resultados ou ocultar conteúdo importante de forma excessiva.
Menos JavaScript desnecessário
Quando a página pode ser renderizada no servidor, essa é uma boa opção para conteúdo que não depende de interação imediata. Server Components, cache e roteamento podem reduzir o volume enviado ao navegador.
A redução de JavaScript precisa ser balanceada. Componentizar tudo no cliente apenas para evitar uma exceção pontual pode aumentar o custo da aplicação sem corrigir a causa principal.
Acessibilidade em atualizações de conteúdo
Se o valor muda depois da hidratação, o elemento pode precisar de uma atualização acessível. Em alguns casos, use uma área com aria-live="polite". A região deve anunciar mudanças relevantes sem interromper a navegação.
FAQ
O que causes hydration mismatch no Next.js?
As causas mais comuns são renderizar data ou hora com fuso horário diferente no servidor e no navegador, usar valores aleatórios, acessar window ou localStorage durante a renderização,|formatar números com idiomas diferentes e usar bibliotecas que assumem um ambiente exclusivamente de cliente. A mensagem do console ajuda a localizar o componente, mas é preciso investigar os valores usados nele.
Hydration mismatch pode quebrar uma aplicação em produção?
Pode. Além do aviso no console, o problema pode provocar mudanças visuais, perda de estado durante a reconciliação, quebra de interações ou problemas de acessibilidade. A gravidade depende do componente afetado. Uma falha em um modal pode atrapalhar mais do que uma diferença em um rótulo secundário.
É necessário usar 'use client' em todo o arquivo para resolver?
Não. Essa diretiva apenas indica que o componente será executado também no navegador. Se o arquivo contiver data aleatória, acesso ao localStorage ou formatação regional, o hydration mismatch continuará existindo. É melhor manter o servidor como padrão e declarar Client Components somente onde houver necessidade real.
Como encontrar qual componente está causando o erro?
Rode o projeto em desenvolvimento e leia o stack trace. Verifique os componentes indicados no console, começando por valores dependentes de data, locale, navegador e estado externo. Você também pode desativar extensões, testar em outro navegador e comparar o HTML inicial com a página depois da hidratação.
Usar useEffect resolve todos os hydration mismatches?
Resolve muitos casos, especialmente quando o valor depende de uma API do navegador. Ele não é uma correção universal. Usado de forma excessiva, pode atrasar a exibição de conteúdo, duplicar requisições e criar outros efeitos colaterais. Também não deve ser usado para esconder erros de serialização ou decisões de arquitetura.
Conclusão
O hydration mismatch no Next.js acontece quando o primeiro render do navegador diverge do HTML gerado no servidor. Data, hora, idioma, armazenamento local, aleatoriedade e integrações com bibliotecas são pontos que merecem atenção especial.
A investigação fica mais eficiente quando você reproduz o erro em desenvolvimento, lê o componente indicado no console e compara o conteúdo inicial com o resultado após a hidratação. Depois, ajuste a origem do valor divergente, mantenha o primeiro render previsível e teste o build de produção.
Se você precisa de ajuda para colocar isso em prática, a Baita Site tem uma equipe especializada em sites, e-commerce, sistemas e inteligência artificial, com domínio total de WordPress e experiência em aplicações web. Fale com a gente e veja como podemos acelerar o seu projeto.
Referências consultadas
- Documentação do React sobre hydrateRoot, referência oficial para entender a hidratação e o comportamento esperado pelo React.
- Documentação do React sobre hydration mismatch, explanations sobre erros de correspondência e casos de incompatibilidade.
- Documentação do Next.js sobre renderização e Server Components, referência oficial sobre a divisão entre componentes de servidor e de cliente.
- Documentação do Next.js sobre
use client, orientação oficial sobre a diretiva e seus efeitos na fronteira entre servidor e navegador. - Documentação do Next.js sobre
next/dynamic, referência sobre carregamento dinâmico de componentes e considerações de renderização no servidor. - React
useSyncExternalStore, documentação oficial do hook indicado para estados externos e integração com APIs do navegador.
Quer ajuda para colocar isso em pratica?
A Baita Site trabalha com sites, e-commerce, sistemas e IA. Quem prefere resolver com acompanhamento, sem ter que virar especialista em tudo, costuma procurar esse tipo de suporte.
Perguntas Frequentes (FAQ)
1. O que causa hydration mismatch no Next.js?
As causas mais comuns são renderizar data ou hora com fuso horário diferente no servidor e no navegador, usar valores aleatórios, acessar `window` ou `localStorage` durante a renderização, formatar números com idiomas diferentes e usar bibliotecas que assumem um ambiente exclusivamente de cliente. A mensagem do console ajuda a localizar o componente, mas é preciso investigar os valores usados nele.
2. Hydration mismatch pode quebrar uma aplicação em produção?
Pode. Além do aviso no console, o problema pode provocar mudanças visuais, perda de estado durante a reconciliação, quebra de interações ou problemas de acessibilidade. A gravidade depende do componente afetado. Uma falha em um modal pode atrapalhar mais do que uma diferença em um rótulo secundário.
3. É necessário usar `'use client'` em todo o arquivo para resolver?
Não. Essa diretiva apenas indica que o componente será executado também no navegador. Se o arquivo contiver data aleatória, acesso ao `localStorage` ou formatação regional, o hydration mismatch continuará existindo. É melhor manter o servidor como padrão e declarar Client Components somente onde houver necessidade real.
4. Como encontrar qual componente está causando o erro?
Rode o projeto em desenvolvimento e leia o stack trace. Verifique os componentes indicados no console, começando por valores dependentes de data, locale, navegador e estado externo. Você também pode desativar extensões, testar em outro navegador e comparar o HTML inicial com a página depois da hidratação.
5. Usar `useEffect` resolve todos os hydration mismatches?
Resolve muitos casos, especialmente quando o valor depende de uma API do navegador. Ele não é uma correção universal. Usado de forma excessiva, pode atrasar a exibição de conteúdo, duplicar requisições e criar outros efeitos colaterais. Também não deve ser usado para esconder erros de serialização ou decisões de arquitetura.