Upgrading a 4-Year-Old Next.js Blog with AI

Upgrading a 4-Year-Old Next.js Blog with AI

Every developer has that one project. The one you built years ago, deployed, and then quietly stopped upgrading it because it just worked.

I built it in 2021 with Next.js 9.5, React 16, and TypeScript 3.8. But I hadn't touched the dependencies since. When I finally ran npm audit, it came back with 136 vulnerabilities. The MDX plugin I used, next-mdx-enhanced, is no longer maintained. The build was still running on Node 12. It was the kind of upgrade that's easy to keep postponing.

The Starting Point

Here's what I was dealing with:

BeforeAfter
Next.js9.515.5
React1618
TypeScript3.85.9
npm audit vulnerabilities1360
MDX pipelinenext-mdx-enhanced (abandoned)next-mdx-remote
Syntax highlighting@mapbox/rehype-prism (prismjs)rehype-pretty-code (shiki)

The Approach: Plan First, Execute Systematically

I used Claude Code to assist me on this task. The first thing we did was analyze every dependency. Map out which ones depended on each other, which ones had breaking API changes, and rank them by upgrade risk.

That analysis produced a 6-phase plan, ordered from zero risk to high risk:

  1. Remove unused dependencies
  2. Patch and minor upgrades
  3. Dev dependency upgrades
  4. Targeted upgrades with API changes (like js-yaml 3 to 4)
  5. Major framework upgrades (MDX pipeline, TypeScript, Next.js, React)
  6. Final push to zero vulnerabilities and assorted small fixes

The workflow was simple: upgrade one dependency at a time, test, commit. No unsupervised batching. If something broke, the blast radius was one commit.

The Hardest Part

In Phase 5, the abandoned next-mdx-enhanced plugin used a layout pattern ((frontMatter) => ({ children }) => JSX) that's completely incompatible with modern Next.js. There was no upgrade path.

Replacing it meant moving 31 MDX files out of src/pages/ into a new content directory, creating dynamic [slug].tsx routes, and refactoring every layout from curried pattern into standard React components. This was the single biggest change.

Adjusting on the Fly

Not everything went according to the original plan. After completing the MDX swap, we re-analyzed the remaining dependencies and reordered the phases. TypeScript could be upgraded independently on Next.js 9.5, so we moved it ahead of the Next.js upgrade itself.

We also caught a regression that wasn't obvious: MDX v2 dropped built-in GitHub Flavored Markdown support. Tables in my mdx files just stopped rendering properly. A quick remark-gfm addition fixed it.

And the prismjs vulnerability, which seemed unfixable because it was a transitive dependency of @mapbox/rehype-prism, turned out to be solvable by switching syntax highlighters entirely. We replaced prismjs with shiki via rehype-pretty-code. That eliminated 3 vulnerabilities in one move.

Results

25 commits. 2 sessions. About half a day of focused work.

The most satisfying part wasn't removing the vulnerabilities, it was that every single commit along the way left the project in a working state.

No "big bang" rewrite.

What I Learned

Codebase upgrades might be the ideal use case for AI-assisted development. They're repetitive, require broad context awareness (peer dependencies, breaking changes across versions, transitive vulnerability chains), and benefit enormously from a systematic approach. These are exactly the things that are tedious for humans and natural for AI.

But here's the nuance: the AI handled the mechanical burden. Reading changelogs, tracking peer dependency conflicts, generating the actual code changes. I provided the strategic direction. When to reorder phases. When to stop and verify every page visually. When a "won't fix" vulnerability actually could be fixed by rethinking the approach entirely.

It's collaborative in the truest sense. Not "AI writes the code while I watch," but "AI handles the tedious, repetitive parts, while I handle the parts that require judgment and taste."

If you have a dusty project sitting in your GitHub with a growing list of audit warnings, it might take less time than you think to bring it back to life.