Porque a mesma data é formatada duas vezes, uma no servidor e outra no navegador, e cada lugar usa o seu fuso horário. Se o servidor roda em UTC e o usuário está no Brasil, em UTC-3, depois das 21 horas de Brasília o servidor já está no dia seguinte. O React percebe a diferença e acusa erro de hidratação, e as datas formatadas só no servidor aparecem um dia à frente. A correção é fixar o fuso no servidor e também dentro do formatador de datas.
O que a documentação diz
Conferi as fontes em 10 de outubro de 2026. Hidratação é o momento em que o React pega o HTML pronto que veio do servidor e o torna interativo no navegador. Para isso ele refaz a renderização e compara com o HTML recebido. A documentação do hydrateRoot diz que o React espera conteúdo idêntico ao do servidor e manda tratar diferenças "como bugs". Ela dá como exemplo justamente uma data formatada com new Date().toLocaleDateString().
O código de erro 425 do React é "Text content does not match server-rendered HTML", ou seja, o texto não bate com o HTML do servidor. Pelo guia de erros do Next.js, usar APIs que dependem do tempo, como o construtor Date(), é uma causa conhecida. O guia oferece três saídas: renderizar o valor só no cliente depois do primeiro desenho, desligar o desenho no servidor naquele componente, ou usar suppressHydrationWarning. Esta última apenas silencia o aviso, e a documentação a chama de "escape hatch" para não ser usada demais. O React também não corrige o texto que ficou diferente.
Sobre o fuso, a MDN diz que toLocaleDateString formata no fuso local, e que o resultado sem argumentos depende da implementação, do idioma e do fuso padrão. A opção timeZone existe para fixar isso. Já a documentação do Node.js diz que a variável de ambiente TZ define a configuração de fuso do processo e aceita nomes como Europe/Paris ou America/New_York. O nome America/Sao_Paulo é do mesmo tipo.
Não vi documentado o fuso padrão de um container. No meu caso era UTC, mas isso depende da imagem que você usa.
O que vi em produção
Em 2 de setembro de 2026, numa aplicação web em que trabalhei, rodei um teste de ponta a ponta no ambiente de produção. A tela mostrava uma lista de linhas com datas, formatadas com toLocaleDateString num componente de cliente. O servidor, num container em UTC, desenhava a lista primeiro. O navegador, em UTC-3, desenhava de novo.
Depois das 21 horas de Brasília, o dia era diferente nos dois lados. O React acusou o erro 425 em cada linha da lista. Além disso, as datas que só existiam no servidor, como "Enviado em", saíam no dia seguinte, sem nenhum aviso.
Um detalhe que atrasou o diagnóstico: nenhum teste local pegou. A minha máquina de desenvolvimento já estava no fuso certo, então servidor e navegador concordavam. O defeito só aparece quando os dois ambientes têm fusos diferentes, e à noite.
Por que acontece
Uma data é um instante no tempo, e o dia que você lê depende do fuso. Às 22h30 em Brasília, em UTC já são 01h30 do dia seguinte. Se o servidor e o navegador usam fusos diferentes, a mesma data vira dois textos diferentes. O React compara os dois textos, vê que não batem e reclama.
A parte pior é o erro silencioso. O que o servidor escreveu sozinho não passa por comparação nenhuma. Ninguém avisa que a data está errada, e o usuário vê o dia seguinte.
O que fazer
- Defina o fuso do container, no arquivo de ambiente:
TZ=America/Sao_Paulo. O Node passa a formatar datas nesse fuso. - Como camada extra, passe o fuso direto no formatador, para o resultado não depender do ambiente:
new Date(valor).toLocaleDateString('pt-BR', {
timeZone: 'America/Sao_Paulo',
})
- Teste com o relógio da máquina deslocado, ou simule o servidor em UTC com
TZ=UTCao subir o ambiente local. Depois das 21h, no horário do Brasil, ou com uma data fixa nesse intervalo, o erro aparece. - Evite
suppressHydrationWarningcomo remédio. Ele esconde o aviso, mas o React não corrige o texto, e o servidor continua escrevendo a data errada. - Se o seu produto atende gente em vários fusos, formatar no servidor com um fuso único mostra a todos o mesmo dia. Nesse caso decida de propósito qual fuso vale, em vez de deixar o ambiente decidir.
Se datas, fusos e erros que só aparecem em produção estão te custando tempo, veja como eu desenvolvo aplicativos e sistemas.
Fontes
- React: erro 425, texto não bate com o HTML do servidor
- React: hydrateRoot, o conteúdo precisa ser idêntico e mismatch é bug
- Next.js: erro de hidratação, causas com Date e uso de suppressHydrationWarning
- MDN: toLocaleDateString usa o fuso local por padrão e aceita timeZone
- Node.js: variável TZ define o fuso do processo