What is Vue's @vue/compat migration build, and how does it let a Vue 2 app run on Vue 3 during an upgrade?
answer
- a Vue 3 build wearing Vue 2 clothes
- which mode it starts in
- deprecation IDs in the dev console
- a bundler alias plus compiler options
- not every app is eligible
basics
~20 s@vue/compat is a Vue 3 build that runs in Vue 2 mode by default: most public Vue 2 APIs keep working, and each changed feature logs a deprecation warning with an ID, so an app migrates one warning at a time.
solid answer
~50 sThe migration build is Vue 3 with configurable Vue 2-compatible behaviour. You move `vue` to 3.x, install `@vue/compat` at the same version, replace `vue-template-compiler` with `@vue/compiler-sfc`, alias `vue` to `@vue/compat` in the bundler, and set `compilerOptions.compatConfig: { MODE: 2 }` for SFC templates, because the template compiler otherwise defaults to Vue 3 behaviour. The runtime starts in `MODE: 2`, so Vue 2 APIs such as `new Vue()`, `$on` or `$listeners` still work, and in development each logs `(deprecation ID) …` with a link to the guide. A few changes are incompatible and must be fixed first (for example `v-if`/`v-for` precedence), and the transition class rename raises no warning at all. It covers only documented Vue 2 APIs, so dependencies built on Vue 2 internals, IE11 support or a custom SSR setup can block it. An app that runs on it can ship to production with a small overhead.
code
ts · 18 lines// vite.config.ts
import { defineConfig } from 'vite'
import vue from '@vitejs/plugin-vue'
export default defineConfig({
resolve: {
alias: { vue: '@vue/compat' }
},
plugins: [
vue({
template: {
compilerOptions: {
compatConfig: { MODE: 2 }
}
}
})
]
})go deeper
Know that @vue/compat is a Vue 3 build that runs Vue 2 code by default and prints deprecation warnings naming each feature that needs changing.
Explain the wiring: same-version packages, the vue alias, and compatConfig MODE 2 in the compiler options because the compiler defaults to Vue 3. Name the four compatibility categories and the silent transition-class change.
Judge eligibility before starting: dependencies on Vue 2 internals, IE11, custom SSR. Plan to collect warnings from dev and test runs, since production is silent.
Treat the migration build as a funded bridge with an exit: decide whether shipping on it is acceptable, how long, and what signals mean the team can drop the alias.
## What the migration build is Upgrading from **Vue 2** to **Vue 3** means dealing with dozens of breaking changes: the global API moved to `createApp`, the component `v-model` contract changed, filters and the `$on` event API were removed, and more. Fixing them all before the app can boot again is a big-bang change. **`@vue/compat`**, which the official migration guide calls **the migration build**, removes that cliff: it is a build of Vue 3 with **configurable Vue 2-compatible behaviour** layered on top. Two properties make it useful: - it **runs in Vue 2 mode by default** — most public Vue 2 APIs behave exactly as before, with only a few exceptions; - every use of a feature that changed or was deprecated emits a **runtime deprecation warning** that names the feature with an ID, so the migration becomes a checklist rather than a guessing game. Compatibility can also be switched on or off **per feature** and **per component**, which is what makes an incremental upgrade possible. ## Wiring it in The migration guide's workflow for a webpack- or Vite-based app: 1. Upgrade tooling if needed (for example `vue-loader` to `^16.0.0`). 2. In `package.json`, move `vue` to Vue 3, add `@vue/compat` at the **same version**, and replace `vue-template-compiler` with `@vue/compiler-sfc`. 3. Alias `vue` to `@vue/compat` in the bundler, so every `import ... from 'vue'` — yours and your dependencies' — gets the compat build. 4. Pass `compilerOptions: { compatConfig: { MODE: 2 } }` to the SFC template compiler. The **template compiler defaults to Vue 3 behaviour** independently of the runtime, so without this, template-level Vue 2 behaviour is not preserved. 5. For TypeScript, add a declaration file that re-exposes Vue's default export and `configureCompat`, since Vue 3's typings have no default export. ## How the warnings work Each warning is printed as `(deprecation GLOBAL_MOUNT) ...` followed by a `Details:` link to the relevant migration-guide page. Useful behaviours: - warnings are **development-only**; a production build prints nothing, so collect them from the dev server and the test suite; - the same deprecation from the **same component type** is reported once, and repeats from other components are shortened to the ID and a count; - the browser console's filter, including negated filters such as `-GLOBAL_MOUNT`, lets you work through one ID at a time; - a warning's component trace shows whether it comes from your code or a dependency. ## Four kinds of compatibility | category | meaning | example | |---|---|---| | fully compatible | Vue 2 behaviour preserved, with a warning | `new Vue()`, `vm.$on`, `$listeners`, filters | | partially compatible | preserved with caveats | `$destroy` (root instance only), `this` in prop default factories | | incompatible | warning only; fix upfront | `v-if`/`v-for` precedence, `<template functional>` | | compat only | preserved, **no warning** | transition classes `v-enter` → `v-enter-from` | The last row is the trap: the transition class rename is the one change the build keeps working silently, so it has to be found with a search for `-enter` and `-leave` selectors. ## Who cannot use it The migration build only covers **publicly documented** Vue 2 behaviour. The guide lists these limitations: - dependencies that rely on **Vue 2 internals** or undocumented behaviour, most commonly private properties on VNodes — such libraries need their own Vue 3 versions; - **IE11**: Vue 3 does not support it, so an app that must support it stays on Vue 2; - **custom SSR**: possible, but much more involved — `vue-server-renderer` gives way to `@vue/server-renderer`, and Vue 3 has no bundle renderer. ## Shipping on it An app that runs on the migration build **can ship to production** before the migration is finished; the guide describes the performance and size overhead as small. That matters when a dependency still needs Vue 2 behaviour. It is still a bridge: the goal is to clear the warnings, switch the app to Vue 3 behaviour and then drop the alias for the standard `vue` build. Two settings make the bridge adjustable while you cross it: - `configureCompat({ ... })`, imported from `vue`, changes the global compat configuration — for example setting a feature ID to `false` to adopt Vue 3 behaviour app-wide, or to `'suppress-warning'` to hide known debt; - a component's `compatConfig` option applies the same settings to one component, so converted components can opt into Vue 3 behaviour while the rest of the app stays in Vue 2 mode.
- Why can a production build of an app on @vue/compat look clean even though plenty of Vue 2 usage remains?The deprecation warnings are development-only: the warning function returns immediately outside dev builds. Production keeps the Vue 2 behaviour but reports nothing, so the only reliable inventory comes from running the dev server and the test suite and collecting the `(deprecation ID)` messages.
- What kind of dependency makes an app ineligible for the migration build, and what do you do about it?One that relies on Vue 2 internals or undocumented behaviour, most commonly private VNode properties. The build covers only documented public APIs and will not be tweaked to cover such cases. You wait for, upgrade to or replace with a Vue 3-compatible version before switching, or keep that dependency's part of the app on Vue 2 behaviour until you can.
saying these in an interview costs you the question
- @vue/compat is a Vue 2 plugin that adds Vue 3 APIs to the old runtime.
- The migration build starts in Vue 3 mode and you opt into Vue 2 features.
- Aliasing vue to @vue/compat is enough; templates compile in Vue 2 mode automatically.
- Every breaking change emits a warning, so a quiet console means the migration is done.
- An app running on the migration build must never be shipped to production.