A developer looking frustrated at code with red error messages and migration blockers highlighted
16 min read Vue 3 Migration

The 7 Blockers That Kill Vue 2 to Vue 3 Migrations

Most Vue 3 migrations don't fail because of one big problem—they fail because of predictable blockers that teams don't see coming. Here are the 7 most common issues and how to handle each one.

Vue 3 migrations have a reputation for being difficult. But the difficulty isn't random—the same problems appear in project after project. Understanding these common blockers before you start is the difference between a migration that takes weeks and one that drags on for months.

This guide covers the 7 blockers most likely to derail your migration, how to identify them early, and proven strategies for each. For timeline and cost context, see our migration timeline guide and cost estimation guide.

The 7 Blockers at a Glance

#BlockerImpactTimeline Effect
1Vuetify 2 Deep IntegrationCritical+50-100%
2Abandoned DependenciesCritical+20-40%
3Mixin SpaghettiHigh+15-30%
4Complex Vuex ArchitectureHigh+15-30%
5Custom Webpack HellMedium+10-20%
6Zero Test CoverageHigh+20-40%
7Part-Time Migration TeamCritical+100-150%
1

Vuetify 2 Deep Integration

The #1 migration killer

Impact: Can double migration timeline and cost

Why This Is So Painful

Vuetify 2 and Vuetify 3 have completely different APIs. Component names, prop names, slot names, event names—everything changed. Teams using Vuetify heavily (100+ components) face a near-complete rewrite of their UI layer.

Warning Signs

  • More than 50 files importing Vuetify components
  • Custom Vuetify theme with SCSS overrides
  • Use of deprecated Vuetify components (v-content, v-layout)
  • Heavy reliance on Vuetify's grid system

The Solution

Create a component-by-component migration map before starting. Migrate in isolation—don't try to run @vue/compat with Vuetify. Budget 40-60% of your migration time just for Vuetify.

Read our Vuetify Migration Playbook →
2

Abandoned Dependencies

The hidden landmines in package.json

Impact: Blocks migration until alternatives are found and implemented

Why This Happens

The average Vue 2 project has 5-8 Vue-specific npm packages that don't support Vue 3. Some are abandoned, some never got updated, some have Vue 3 versions with completely different APIs. Each one needs to be addressed before migration can complete.

Commonly Abandoned Packages

  • × vue-moment
  • × vue-clipboard2
  • × vue-lazyload
  • × vue-meta (v2)
  • × vue-scrollto
  • × vue-notification
  • × vue-js-modal
  • × vue-multiselect

The Solution

Run a dependency audit before estimating timeline. For each Vue-specific package, determine: Does it have a Vue 3 version? Is there an alternative? Can we remove it entirely? Can we build it ourselves?

npm ls | grep vue

List all Vue-related packages and check each one for Vue 3 compatibility.

3

Mixin Spaghetti

When code reuse becomes code confusion

Impact: 2-4 weeks of refactoring before migration can proceed

Why This Is Problematic

Mixins were Vue 2's answer to code reuse. The problem? They create implicit dependencies, naming conflicts, and untraceable data flow. Codebases with 20+ mixins, some chained 3-4 levels deep, become nearly impossible to migrate safely.

The Mixin Problem

// Where does `formatDate` come from?
// Where does `userData` come from?
// What if two mixins both define `loading`?

export default {
  mixins: [FormMixin, ValidationMixin, UserMixin, AnalyticsMixin],
  computed: {
    displayDate() {
      return this.formatDate(this.userData.created)  // 🤷
    }
  }
}

The Solution

Convert mixins to composables before or during migration. Composables have explicit imports—you can see exactly where each piece of functionality comes from.

// Composable: explicit, traceable, typed
import { useForm } from '@/composables/useForm'
import { useUser } from '@/composables/useUser'
import { formatDate } from '@/utils/dates'

const { userData } = useUser()
const { validate, errors } = useForm()
Learn about Composition API →
4

Complex Vuex Architecture

More than just "install Pinia"

Impact: 2-4 weeks to migrate to Pinia, longer with plugins

When Vuex Gets Complicated

Simple Vuex stores migrate easily. But stores with 15+ modules, nested namespacing, custom plugins, and middleware are a different story. Custom Vuex plugins for features like undo/redo or persistence can take weeks to reimplement in Pinia.

Complexity Indicators

  • More than 10 Vuex modules
  • Nested modules (modules inside modules)
  • Custom Vuex plugins (persistence, logging, etc.)
  • Heavy use of rootGetters and cross-module dispatch
  • Dynamic module registration

The Solution

Migrate one module at a time. Pinia and Vuex can coexist during migration. Start with leaf modules (no dependencies), work toward root modules.

Read our Vuex to Pinia Migration Guide →
5

Custom Webpack Hell

Years of accumulated build complexity

Impact: 1-2 weeks of build tool debugging

The Build Tool Dilemma

Teams that ejected from Vue CLI or added heavy customizations face a choice: migrate the entire Webpack config to Vite, or update it for Vue 3. Neither is fun. Configs with 500+ lines of custom Webpack rules take significant time to untangle.

Common Customizations

  • Custom loaders for specific file types
  • Module federation or micro-frontend setup
  • Specific optimization plugins
  • Custom dev server middleware
  • Legacy browser polyfill chains

The Solution

Document every customization before starting. For each one, determine: Is it still needed? Is there a Vite equivalent? Can we simplify? Consider this an opportunity to clean up years of accumulated build complexity.

6

Zero Test Coverage

Flying blind through a major rewrite

Impact: Higher risk of production bugs, longer QA cycles

The Testing Reality

Many Vue 2 codebases have less than 20% test coverage, and some have zero tests. Without tests, you're flying blind during migration—every change could break something, and you won't know until a user reports it.

The Testing Catch-22

"We can't migrate without tests, but we can't write Vue 2 tests when we're about to migrate to Vue 3."

This is a real dilemma. The answer depends on your risk tolerance and timeline.

The Solution

Option A:

Write E2E tests first (Cypress/Playwright). These survive the migration and catch regressions in user flows.

Option B:

Migrate first, then write tests for Vue 3. Faster, but riskier. Requires thorough manual QA.

Option C:

Focus on critical path tests only. Identify your 10 most important user flows and test those.

7

Part-Time Migration Team

The organizational blocker

Impact: 2-3x longer timeline, higher total cost, team burnout

Why Part-Time Fails

Most teams attempt migration while simultaneously shipping features. "We'll work on the migration when we have time." The problem: there's never time. Context switching destroys momentum. Migrations drag on for months, sometimes over a year.

The Part-Time Penalty

Dedicated Team

8 weeks

Focused, consistent progress

Part-Time (50%)

20+ weeks

Context switching, stalls

The Solution

Treat migration as a project, not a side task. Either dedicate developers full-time for a shorter period, or hire specialists to handle it while your team focuses on features.

See realistic timeline estimates →

How to Identify Your Blockers Early

The worst time to discover a blocker is mid-migration. Here's how to find them before you commit to a timeline:

1

Run a dependency audit

Check every Vue-related package for Vue 3 support. Create a spreadsheet with status: Compatible / Needs Replacement / Needs Custom Solution.

2

Count your Vuetify/BootstrapVue components

grep -r "v-btn\|v-card\|v-dialog" --include="*.vue" | wc -l — If this number is high, plan accordingly.

3

Map your mixins

List every mixin and which components use them. Identify naming conflicts and dependency chains.

4

Document your Vuex complexity

Count modules, identify plugins, check for nested namespacing and dynamic registration.

5

Review your build configuration

Identify all custom Webpack/Vue CLI configurations. Note any that will need special attention.

6

Check test coverage

Run coverage report. If it's low, factor in additional QA time or write E2E tests first.

Don't Want to Do This Yourself?

Our Migration Readiness Audit identifies all 7 blockers in your codebase, provides specific remediation strategies, and gives you a realistic timeline and fixed-price quote.

✓ All 7 blockers assessed ✓ Remediation strategies included ✓ Fixed-price quote

Conclusion

Every Vue 2 migration has challenges. But the difference between a migration that takes 8 weeks and one that drags on for 8 months usually comes down to whether these 7 blockers were identified early.

Vuetify integration. Abandoned packages. Mixin spaghetti. Complex Vuex. Webpack customization. No tests. Part-time teams. If you're planning a migration, audit your codebase for these issues before you estimate timeline and cost.

The blockers won't go away if you ignore them. But if you know they're coming, you can plan for them—and that makes all the difference.

Related Guides