A real migration log from this very site — three major version jumps, one silent bug that returned blank pages, and what it means for your website too.
Wed Aug 19 2026
19 min readThree major version jumps, one silently broken page type, and the lesson every business owner with an older website should take from it.
This site was running on Next.js 13, released back in 2023. Nothing was visibly wrong with it — it loaded, the pages worked, visitors couldn't tell the difference. But under the hood it was three major versions behind, on a framework that ships security and performance fixes with every release. So I upgraded it: Next.js 13 to 16, React 18 to 19, Tailwind CSS 3 to 4. Here's what actually happened, because "I upgraded my dependencies" undersells how much can quietly go wrong.
Tailwind CSS 4 moved its PostCSS plugin into a separate package. The old config pointed at the old package name, so the very first production build after the upgrade failed outright with a build error. This is the good kind of breaking change — loud, immediate, impossible to miss. Fifteen minutes of reading the migration guide and it was fixed.
The scarier bug didn't throw any error at all. Since Next.js 15, the params object that dynamic pages receive (the part of the URL like the article slug in /blog/my-post) changed from a plain object to a Promise. Code written for the old behavior doesn't crash — it just silently receives undefined instead of the actual slug.
The result: every single blog post, project, and service detail page on this site was quietly serving blank content. Not an error page. Not a 404. Just... nothing, where a title and article should have been. It passed a full production build with zero warnings. The only way to catch it was to actually click into a page and notice something was missing.
That's the part worth sitting with if you own a website: a broken build is annoying but obvious. A silently broken page is invisible to you, invisible to your developer if they don't test by hand, and only visible to a visitor who happened to click the wrong link at the wrong time — right when they were deciding whether to trust your business.
The last bug was the strangest. Next's older image component shows a blurred placeholder while the real image loads, then fades it in. After the upgrade, that fade-in stopped firing reliably — the real image would finish loading successfully in the background, but the blurred placeholder just stayed on screen forever. Confirmed by checking the browser's own record of what loaded: the image was there, complete, ready — just never shown. Migrating to the newer image component fixed it outright.
Most small business websites don't get touched again after launch. That's fine for a while — until the framework underneath it moves on far enough that upgrading isn't optional anymore, and by then, three or four major versions have piled up at once, each with its own quiet breaking changes like the ones above. The fix isn't "never update." It's having someone who actually clicks through every page after a change, instead of trusting a clean build log to mean everything works.
If you're not sure how old the software under your own site is, or when it was last actually tested end-to-end rather than just "still loading fine," that's a reasonable thing to ask whoever built it — or to have a second set of eyes check.