Skip to content
All services
Service 01 / 03 Available · part-time · B2B

Vue 2 to Vue 3 migration

Vue 2 reached end of life on 31 December 2023. I plan and deliver migrations to Vue 3 that are fast and maintainable after the switch, not just compiling.

Engagement
Available · part-time · B2B
Stack
Vue 3 · TypeScript · TanStack Query · SignalR · Biome

Vue 2 is end of life. Your application still has work to do.

Vue 2 reached end of life on 31 December 2023, and Nuxt 2 followed on 30 June 2024. The software built on top of them did not disappear with those dates. Customers still use it, new features still need to be delivered and the existing code still has to be maintained.

That is where the real migration problem begins. As time goes on, upgrades become harder, old dependencies stay in place longer and parts of the codebase become increasingly expensive to change. A migration is a way to remove that constraint, but it should be planned around the application you actually have rather than treated as a simple framework upgrade.

I have been building production frontends for more than a decade, with deep experience in Vue and Nuxt. For me, a Vue 2 to Vue 3 migration is an engineering project with a clear outcome: move the application to a healthier codebase without creating another legacy system along the way.

Incremental migration or a rewrite?

There is no universal answer. The right approach depends on the codebase, the product and how the team needs to keep working while the migration is happening.

  • Which parts of the application are still changing? Areas that receive new features every month are usually worth restructuring carefully. Stable parts may only need the changes required to run cleanly on Vue 3.
  • Can feature development stop? If the product has to keep moving, an incremental migration can allow the team to ship throughout the transition instead of waiting for a long rewrite to finish.
  • What problems are you actually trying to solve? If the current application suffers from hidden coupling, unclear data flow, inconsistent conventions or difficult module boundaries, changing Vue versions will not remove those problems by itself.
  • Where are the real boundaries in the code? The answer determines whether the application can be migrated in sensible pieces or whether the current structure makes a larger rewrite more practical.

I would rather make that decision after a short look at the repository than three months into a migration.

What I look at before changing the code

A migration gives you a rare opportunity to question parts of the application that have been left in place simply because they were already there. Before moving components from Vue 2 to Vue 3, I look at the structure around them.

That includes module boundaries, shared dependencies, state management, API access, query and cache patterns, reusable components and the conventions developers rely on every day. The goal is to know what should move as-is, what should be cleaned up during the migration and what should be removed altogether.

This is also where I look for dependencies that make a gradual migration harder. Circular imports, shared modules with unclear ownership and application-wide utilities can all turn a seemingly simple migration into a chain of unrelated changes.

Migration is also a chance to improve the product

Not every legacy replacement starts with Vue 2. I have also replaced older frontend technology by building its successor from scratch.

One example was a weekly meal planner that replaced a KnockoutJS application. I proposed drag and drop as the primary interaction, turning a workflow based on clicking through forms into one where a week could be planned by rearranging the interface directly.

The same principle applies to a Vue 2 migration. When a screen already needs substantial work to fit the new architecture, it is worth asking whether the current interaction still makes sense. A migration can be the right moment to improve a frustrating workflow rather than faithfully reproducing it in newer technology.

A rewrite can still inherit the old problems

One of the most useful migration lessons I have seen came from a large Vue 3 rewrite for a catering enterprise. The application had a modern stack, feature-based organisation, TanStack Query and real-time updates through SignalR. It was also slow before it reached production.

The causes were not specific to Vue itself. Nested loops performed unnecessary work, some watchEffect calls triggered themselves repeatedly due to chain reactions, TanStack Query was being used as a global event bus and reactive queries created request waterfalls in which one request led directly to another.

I separated responsibilities between modules and views, introduced stricter project rules with Biome and git hooks, centralised API clients, queries, mutations and query keys in one typed data layer, and built an invalidation mechanism driven by SignalR events. Each message could then invalidate only the queries affected by the change.

The result was a Vue 3 application without the remaining request waterfalls, together with clearer rules around how data moved through the system. The full case is described in the performance rescue case study.

That is the risk of treating migration as a syntax exercise: if the old architecture is copied into the new codebase, the application may be newer without actually becoming easier to maintain.

Nuxt and the structure around the application

For many teams, moving to Vue 3 also means moving to a newer Nuxt stack. I have built applications with Nuxt 4 and Payload CMS 3, including a site for an animal shelter using Postgres, Lexical, a pnpm monorepo, a shared Storybook component library and Docker-based deployment.

That experience matters during a migration because the target architecture also needs to be practical to develop and deploy. The goal is not simply to get the application running on a newer version of Vue, but to leave the team with a codebase and development setup they can continue to evolve.

I also built rds, an open-source Rust tool for finding circular dependencies in Node.js and TypeScript applications. I use the same kind of dependency analysis when planning migrations: understand where the code is coupled first, then choose migration boundaries that keep the work manageable.

What the migration should leave behind

A successful migration is more than a collection of components rewritten in Vue 3. The result should make the next piece of work easier than it was in the old codebase.

  • A healthier Vue 3 architecture. Clearer module boundaries, a sensible data layer and fewer hidden dependencies.
  • Consistent engineering rules. Linting, formatting, type checking and git hooks run automatically, so the quality of the code does not depend on how closely someone happens to review a pull request.
  • A migration plan that reflects the real application. What should move first, what can wait, what needs redesign and what is no longer worth carrying forward.
  • A team that can continue without me. I work alongside the developers on the project and explain the decisions behind the migration, so the knowledge becomes part of the team rather than leaving with the consultant.

If you are unsure whether your application needs a full migration, a more incremental approach or a broader architectural review, I can start with the codebase and help establish what is actually worth changing. A frontend performance audit can also be useful when performance has become one of the reasons for considering a rewrite.

If the application is part of a larger multi-application platform, my work with micro-frontend architecture is useful for the same reason: the migration needs to fit the system around the application, not just the components inside it.

I am available part-time, on B2B terms, working remotely. Tell me about your Vue 2 application and I will reply within one business day.

Let's look at your frontend.

Part-time, B2B, remote. I reply within one business day.

Let's talk