Akash DahadProduct engineer · India

Upgrading Next.js 13 to 15: why, what it fixes and how

Field notes Frontend and the web 4 min read
Next.jsSecurityUpgradesDependencies

We found critical security issues in our Next.js 13 app. Why we moved to 15 instead of patching, what the upgrade fixes, the steps and what to watch for.

When we scanned our main app’s dependencies, the report was long: 79 known vulnerabilities, some of them critical, and several in Next.js 13 itself. We moved the app to Next.js 15, and the count dropped to 53.

This is why we upgraded instead of patching, what an upgrade like this does and doesn’t fix, and the steps I’d follow again.

Why upgrade instead of patching 13

Next.js supports the current major version and keeps the previous one in maintenance, which means critical fixes and security updates only. Everything older is outside the policy. Version 13 had fallen out of that window. A few severe issues did get a late 13.x patch, but that’s the exception, and you can’t plan a product around exceptions.

Staying on 13 meant chasing fixes one at a time, waiting to see which ones would ever arrive. Moving to a supported version fixes the framework’s known issues in one change, and keeps the fixes coming.

What kind of issues pile up on an old version

To make that concrete, these are examples of advisories published against Next.js versions in the 13 range:

  • Middleware authorization bypass. A crafted request could skip the middleware, so any access check that lived only in middleware didn’t run. It was rated critical.
  • Server-side request forgery in Server Actions. A crafted request could make the server fetch a URL the attacker chose.
  • Cache poisoning in the Pages Router. Under certain conditions, a response meant for one request could be cached and served to others.

Not every advisory applies to every app. Each one depends on which features you use and how you host. That’s exactly why it’s easier to be on a version where all of them are fixed than to work out, one by one, which ones you’re exposed to.

What an upgrade fixes, and what it doesn’t

Sort the findings before you start. They fall into three groups:

  1. In the framework itself. The upgrade fixes these.
  2. In packages the framework brings in. The upgrade usually fixes many of these, because the new version pulls in newer packages.
  3. In your own dependencies. The upgrade does nothing for these. They need their own updates.

That split tells you how far the upgrade alone will get you before you spend a week on it. It’s also why our count went down, not to zero. The rest is a separate job.

How to upgrade, step by step

  1. Scan and save the result. Run your dependency scanner and keep the report, so you can compare afterwards.
  2. Read the upgrade guides for every version in between. Going from 13 to 15 means reading the guides for 14 and for 15. Both are short.
  3. Go one major version at a time. 13 to 14 first, then 14 to 15. When something breaks, you know which version broke it.
  4. Use the codemods. Next.js ships scripts that rewrite your code for most breaking changes, and its upgrade command offers the ones that apply.
  5. Upgrade React only when your router needs it. The App Router in 15 needs React 19. The Pages Router doesn’t, so a Pages Router app can take the Next.js upgrade first and React later. One big upgrade at a time is plenty.
  6. Freeze features while you upgrade. Merging new work into a moving target makes every failure harder to place.
  7. Test a production build, not just the dev server, and click through the flows customers notice first, like sign-in.
  8. Scan again. For every finding that’s left, write down whether your code actually reaches the vulnerable part, and what the plan is.

What to watch out for

  • Node.js versions. Next.js 14 and 15 each need a newer Node.js. Check your CI and your servers, not just your laptop.
  • Removed and moved features. A few things were renamed or removed along the way, such as the old static export command and the separate font package. The codemods catch most of them, and the build tells you about the rest.
  • Defaults that change quietly. In 15’s App Router, some request functions became async, and data fetches and GET route handlers are no longer cached by default. Nothing errors, but pages can behave or perform differently.
  • Peer dependency errors. Libraries pinned to older React or Next.js versions will complain. You can force past the warning, but write down every package you forced, because each one is something to come back to.
  • Failures that only show up in a build. Some problems never appear on the dev server.

The lesson

Staying current is a security decision, not just a features one. The longer an app sits on an unsupported version, the more fixes it misses, and the bigger the eventual upgrade gets.

We later moved to Platform v2, a new web app in one monorepo. The rest of this app’s story is in the frontend case study.

Quick answers

Is Next.js 13 still supported?
No. Next.js supports the current major version and keeps the previous one in maintenance for security fixes. Version 13 is outside that window, so fixes for it are rare exceptions, not something to plan on.
How do I upgrade from Next.js 13 to 15?
Scan your dependencies first, read the upgrade guides for 14 and 15, and go one major version at a time with the official codemods. Then test a production build and scan again.
Does Next.js 15 require React 19?
The App Router in Next.js 15 requires React 19. The Pages Router still works with React 18, so a Pages Router app can upgrade Next.js first and React later.
Does upgrading Next.js fix security vulnerabilities?
It fixes known issues in Next.js itself and often in the packages it brings in. Issues in your own dependencies stay until you update or replace those packages.
The case study behind this post Building the frontend to be configured, not customised 79 → 53 known vulnerabilities