Upgrading Nuxt v3 to v4 under 30 minutes

Posted 18 days ago
Return to overview
Astronauts

TL;DR: I upgraded a 32k LOC Nuxt app from v3 to v4 in 29 minutes of actual work. Here's how it went and what I learned.

I'm maintaining a reasonably sized Nuxt application - not massive, but substantial enough to make upgrade decisions matter. We're talking about a project (excluded tests here) with 32k lines of code spread across 173 files, with a healthy mix of 72 Vue components and 44 TypeScript files. The dependency footprint includes 34 production dependencies plus 7 development ones. So, not that big, which makes it a perfect candidate for an upgrade scenario!

Since I was already on a very recent Nuxt 3 version, I figured this would be a good time to take the plunge into Nuxt 4. I was curious to see how smooth the migration path would be.

Spoiler alert: smoother than expected, but with a few interesting bumps along the way!

What's a major framework upgrade?

Let's talk about what we're actually dealing with when we say "major version upgrade":

A major framework upgrade typically involves breaking changes that require intentional code modifications. These aren't just bug fixes or new features - they're architectural shifts that can affect how your application builds, runs, and behaves.

The upgrade usually touches several areas:

  • API Changes: Method signatures, configuration options, or component props that work differently

  • Build System Updates: How your code gets compiled and bundled

  • Dependency Ecosystem: Other packages in your stack that need to catch up

  • File Structure: Sometimes the way you organize your code needs to change

  • Type Definitions: If you're using TypeScript, the type contracts might shift

In Nuxt's case, version 4 represents a significant step forward in their architectural vision, building on the solid foundation of Nuxt 3 but with some important refinements and improvements.

It's worth noting that Nuxt no longer follows Vue's major version numbers like it used to. In the early days, Nuxt 2 corresponded with Vue 2, and there was an expectation that framework versions would stay aligned. However, the Nuxt team realized this created unnecessary coupling between two different release cycles. Vue focuses on the reactive framework and component system, while Nuxt deals with the full-stack application layer, build tooling, and developer experience. These concerns evolve at different paces and have different breaking change considerations. By decoupling version numbers, Nuxt can iterate on its own architectural improvements without being constrained by Vue's release timeline, and vice versa. This independence actually benefits both ecosystems - Vue can focus on its core strengths while Nuxt can evolve its application framework features more naturally.

The upgrade journey: an honest timeline ā±ļø

12:17 - The optimistic start

Like any good developer, I started with the official approach:

npx nuxt upgrade

Well, that failed. Not entirely surprising: official upgrade tools are great when they work, but they can't account for every project's unique setup. No worries, let's move to plan B.

Manual approach (plan B):

npm install nuxt@^4.0.0npx codemod@latest nuxt/4/migration-recipe

The codemod did its thing, making some structural changes, but I held off on running npm install just yet. Sometimes it's better to see what breaks before fixing the dependencies.

12:23 - Dependency updates

The dependency updates began in earnest. Started with a general npm install, which highlighted the peer dependency conflicts I expected. Then I got targeted with the packages that needed attention:

npm install @nuxt/scripts@latest npm install @vueuse/nuxt@latest

PrimeVue also needed a bump to stay compatible.

12:36 - File reference fixes

This is where the real work began. Nuxt 4 has some differences in folder structure and conventions. I spent time updating import paths and file references. Nothing dramatic, just the kind of changes that codemods sometimes miss.

12:40 - Types and resolvers

The TypeScript definitions needed some love, and a few resolver configurations had to be updated. Again, these were focused changes rather than broad rewrites.

12:46 - Stop the clock! šŸŽ‰

App was running smoothly. Total active work time: 29 minutes.

What made this upgrade smooth?

Several factors contributed to the relatively painless experience:

  • Recent starting point: I was already on a very recent Nuxt 3 version, which meant I wasn't carrying forward old technical debt or deprecated patterns.

  • AI-assisted troubleshooting: I used Claude to help resolve some errors and interpret documentation. Having an AI assistant review error messages and suggest solutions definitely accelerated the debugging process.

  • Focused scope: The changes were mostly mechanical - updating imports, tweaking configurations, and bumping dependencies. No major architectural rewrites required.

  • Good foundation: The existing codebase was well-structured with clear separation of concerns, which made it easier to identify what needed changing.

Lessons learned and practical tips āœļø

  • Start with the official tools, but don't depend on them: While the nuxt upgrade command failed for me, but that's not necessarily a bad thing. Sometimes manual upgrades give you better control and understanding of what's changing.

  • AI assistance is a game-changer: Having Claude help interpret error messages and suggest solutions significantly reduced the time I spent stuck on individual issues. It's like having a very knowledgeable pair programming partner who's read all the documentation.

  • Dependency timing matters: Being on a recent version of the previous major made all the difference. If I'd been on an older Nuxt 3 version, I might have had to deal with accumulated breaking changes rather than just the v3 to v4 delta.

  • Think before you code: Taking time to understand what needs changing rather than just reacting to each error as it comes up leads to more focused solutions.

  • Focus on the critical path: I didn't try to optimize everything at once. Get it working first, then improve. The upgrade revealed some areas for future optimization, but those weren't blocking issues.

  • Choose the right moment: I waited a while before running the upgrade, since I had a couple of dependencies (PrimeVue mostly) that needed some time for compatibility. This ensures that some of the initial friction and kinks are ironed out before I apply them.

Why this matters šŸŽÆ

Framework upgrades often feel like massive undertakings, but this experience reinforces that they don't have to be. The key is preparation and approach:

  • Know your starting point: Understanding your codebase size, dependency footprint, and current version helps set realistic expectations.

  • Use the right tools: Codemods, AI assistance, and good version control make the process much more manageable.

  • Accept that not everything moves at the same pace: Some packages in the ecosystem might lag behind major releases, and that's okay. You can work around it or wait for compatibility updates.

  • Measure what matters: The 29-minute active work time is a useful metric, but so is the fact that the app remained stable and performant after the upgrade.

The bigger picture 🌌

Most of the upgrade is owed to the work of the Nuxt team. Big applause to all contributors!

  • The Nuxt team has invested heavily in migration tooling

  • The ecosystem has caught up with v4 compatibility

  • The codebase was already following modern patterns

  • I had the right tools and assistance available

Not every upgrade will be this smooth, but when the conditions align, it's surprisingly achievable to make major version jumps without major drama. I remember the upgrade from v2 to v3. This was way better, which was the intention of having shorter release cycles in the first place! Having a community which prioritizes Developer Experience is such a joy to work with! šŸ’š

Enjoyed this article? I’m available for part-time remote work helping teams with architecture, web development (Vue/Nuxt preferred), performance and advocacy.

Return to overview
Buy Me A Coffee
If you like my content, consider buying me a (small) coffee! ā˜•ļø