Víctor Sans de Amores

Home / Cases / The render the browser threw away

The server rendered the page and the browser threw it away

29 August 2026 menudojuego.com — my own project Next.js 15 · React · Docker
The 'upcoming releases' block on menudojuego.com: six game cards, each with its release date written out in full and a countdown in days, hours, minutes and seconds
The upcoming releases block on menudojuego.com, today. Every one of those dates is written twice: once on the server and once in the visitor's browser. For a while the two did not agree.

The site renders on the server and React then hydrates it in the browser: it paints the same tree again and compares it against the HTML that arrived. If they differ it does not patch the difference — it throws the server HTML away and repaints the whole page on the client. That is the expensive way to do server rendering: you pay for the render and then bin it.

The console showed React error #418, which is that mismatch in minified form. Some loads had it, some did not, so I put it off for weeks.

The part worth writing down

What broke the "sometimes yes, sometimes no" was loading the home page with Playwright while changing the browser's time zone. It stops being intermittent the moment you look at the right variable:

The measurement from that day. The server sits in Madrid: everybody had the bug except me.
4
time zones tested, 3 with the page broken
2
different days written for the same instant
6
files touched to fix it
5
tests keeping it from coming back

The cause was repeated across half the project, in the most innocent-looking way a date can be written:

Real output, run while writing this case. Without timeZone, Intl uses the zone of whatever environment runs the code: the container runs in Madrid, the visitor runs in their own.

From 22:00 UTC onwards the two halves wrote different days for the same date. React compared "16 de agosto" against "15 de agosto", saw two strings that do not match, and did exactly what it is supposed to do.

The most annoying detail: the PageSpeed robot measures in UTC. So the score I kept looking at was always the bad case, while in my own browser, in Madrid, the site was fine. I spent that time on images, fonts and bundle size, because the numbers did not match what I could see.

The fix

My first attempt was to pin TZ=Europe/Madrid in the container. The error went away, of course: I am in Madrid. That fixed nothing, it just made the server agree with me. For someone in Mexico it was still broken.

The real fix was the boring one: a formatearFecha() function with the zone written into it, and every date on the site going through it instead of calling Intl directly. Six files, 94 lines added and 14 removed. What matters is not that the zone is Madrid, it is that it is one fixed zone, the same on both sides.

Plus a regression test, because you cannot see this failure by looking at the screen:

The test formats the boundary date in three zones and fails if any of them drifts. It is what stops this coming back in six months, when someone writes a new date without thinking about it.

Where it stands today

As of 29 August 2026, loading the production home page 16 times across Madrid, UTC, Los Angeles and Tokyo: the day is written identically in all four and the <h1> is present in every one. The time zone mismatch is gone.

What is still wrong, before you find it yourself

In those same 16 loads, 2 still produced a #418. It no longer follows the old pattern though: it comes and goes within the same zone, so it is a different failure from the one this case is about. My guess is something computed from a running clock rather than a fixed date. Unresolved.

And one place still has the original bug intact: the my account page, a client component that still formats dates without naming a zone. It sits behind the login, so neither the PageSpeed robot nor many people ever reach it. That explains why it is still there; it does not make it right.

Stack: Next.js 15, React, Docker, self-managed VPS. My own project, nothing confidential — which is why it can be told in full, numbers and tests included.

Is your site slow in a way the numbers do not explain?

A bad score you cannot reproduce in your own browser, an error that only shows up "sometimes", a page that quietly rebuilds itself. That is exactly the kind of work I do. I reply within one working day.