Migration Rules
This guide explains how vp migrate updates dependencies, source imports, and package-manager configuration in existing Vite+ projects. See the migration guide for the complete command overview.
Before You Migrate
- Run
vp upgradebefore migrating an existing Vite+ project. A stale local CLI does not contain the new migration rules; migration delegates to the global CLI when the local version is older. - Upgrade the project to Vite 8+ and Vitest 4.1+ when necessary.
- Run
vp migratefrom the workspace root. Use--no-interactivein automated environments. - Review every changed manifest, package-manager config, source rewrite, and generated lockfile.
- Validate with
vp install,vp check,vp test, andvp build.
Running the migration again after a successful migration should not produce another diff.
Dependency Versions
vite-plusis pinned to the concrete version of the CLI running the migration, not thelatestdist-tag.- The
vitealias must target@voidzero-dev/vite-plus-corefrom the same Vite+ release. - A catalog-backed manifest may contain
catalog:or an existing named catalog reference. The referenced catalog value must still be updated to the concrete toolchain target. - Preserve deliberate protocol pins such as
workspace:,file:,link:,npm:,github:, Git URLs, and HTTP URLs. - Reconcile every workspace package, not only the root manifest. Shared overrides and catalogs stay at the workspace root; direct peer providers belong in each package that needs them.
Dependency Changes
| Dependency | Migration rule |
|---|---|
vite-plus | Add it where the package is migrated. Re-pin plain ranges to the current concrete target, directly or through a catalog. Preserve deliberate protocol pins. |
vite | Keep existing declarations. With pnpm, add a direct dev dependency to every package that depends on vite-plus and does not already declare vite. Point managed edges and the shared override to the matching @voidzero-dev/vite-plus-core target. |
vitest | Remove it in the common node-mode case because vite-plus provides it transitively. Keep or add an exact bundled version only in packages with direct Vitest requirements. |
@vitest/* | Align lockstep packages that the project directly lists to the bundled Vitest version. Prefer the package's existing catalog reference when its catalog owns that package; otherwise write the concrete version. |
@voidzero-dev/vite-plus-test | Remove all dependency, override, resolution, and catalog aliases. Rewrite imports to the current vite-plus/test* surface. |
Vite and Overrides
Package-manager overrides do not synthesize dependency edges. Under pnpm, every package that lists vite-plus in dependencies or devDependencies must also declare vite, unless it already has a vite entry in dependencies, devDependencies, optionalDependencies, or peerDependencies. Otherwise, pnpm can auto-install upstream Vite to satisfy Vitest's required vite peer, creating separate Vite+, Vite, and Vitest instances. vp migrate adds a missing vite entry to devDependencies; the workspace override redirects it to Vite+ core.
Do not remove a direct vite declaration merely because a root override exists. Normalize existing plain or stale aliases while retaining named catalog references. The general rule above is specific to pnpm. Bun mirrors its core alias as a direct dependency for its peer resolver, while npm browser-provider layouts may need a top-level edge so nested Vitest packages can resolve vite.
When Vitest Is Directly Required
Keep or add package-local vitest at the exact bundled version when any of the following is true:
- an installed dependency has a non-optional
vitestpeer, whether exact or a range; - the package uses Vitest browser mode or an opt-in browser provider;
- source or TypeScript configuration retains an upstream
vitestreference; - the package declares
@nuxt/test-utils; or - dependency metadata is unavailable and an existing direct
vitestmight be satisfying an unknown required peer.
vp migrate checks installed peer metadata, so integrations such as vite-plugin-gherkin are handled even though their names do not contain vitest.
When a package directly requires Vitest:
- add
vitestto that package, not indiscriminately to every workspace package; - use the existing catalog reference when supported, otherwise use the exact bundled version; and
- keep a matching workspace override or resolution so the graph uses one Vitest version.
A peer declaration alone does not install Vitest. If a surviving peerDependencies.vitest uses a catalog entry that migration will remove, resolve it to the public peer range first.
Vitest Ecosystem Packages
Official current @vitest/* packages generally publish in lockstep with Vitest. Align packages the project directly installs, including @vitest/coverage-v8, @vitest/coverage-istanbul, @vitest/ui, and @vitest/web-worker.
Catalog handling is package-specific:
- preserve
catalog:and namedcatalog:<name>dependency references when the corresponding catalog already defines that package; - update that catalog entry to the bundled Vitest version; and
- use the concrete bundled version when no catalog owns the package.
Do not align independently versioned or obsolete packages:
@vitest/eslint-pluginhas its own version line;@vitest/coverage-c8stopped at an older release and has no Vitest 4 version; and- third-party
vitest-*integrations keep their own compatible package versions, although their required Vitest peer may require direct provisioning.
The base @vitest/browser runtime and @vitest/browser-preview are bundled by Vite+ and should be removed as direct dependencies. The Playwright and WebdriverIO providers remain opt-in: keep or add the provider at the bundled Vitest version and ensure its playwright or webdriverio peer is installed.
Object-valued nested npm and Bun overrides are preserved because they are user-defined scopes rather than scalar version pins.
Source Rewrite Rules
- Rewrite ordinary
vitestandvitest/*imports tovite-plus/test*. - Rewrite scoped browser imports to the corresponding
vite-plus/test/browser*exports and provision opt-in providers when needed. - Leave existing
vite-plus/test*imports unchanged. - Do not rewrite
declare module 'vitest'ordeclare module '@vitest/browser*'. Module augmentation must retain the upstream module identity. - Retained references such as
compilerOptions.types,require.resolve,import.meta.resolve, andvitest/package.jsonrequire package-local Vitest. - In a package that declares
@nuxt/test-utils, preserve everyvitestandvitest/*module specifier package-wide. Its transform requires the upstream identity and can otherwise inject a duplicateviimport. This exception does not apply to sibling packages or scoped@vitest/browser*imports.
The prefer-vite-plus-imports lint rule follows the same Nuxt exception, so lint autofix preserves these imports.
Package-Manager Rules
pnpm
- pnpm 10.6.2+ uses
pnpm-workspace.yamlas the single source for supported root settings. Migration moves recognizedpackage.json#pnpmfields there, including overrides, peer rules, patch settings, package extensions, architecture and build policy, audit/update configuration, and configuration dependencies. It removes thepnpmobject when it becomes empty and preserves unknown keys that may belong to other tooling. - Before pnpm 10.6.2, migration retains these settings in
package.json#pnpm. General workspace-setting support started in pnpm 10.5.0, but overrides required 10.5.1 andpeerDependencyRulesrequired 10.6.2. pnpm 11 no longer reads the legacy package.json settings. - Migration keeps dependency references, default and named catalogs, overrides, and
peerDependencyRulesconsistent. - Each package that lists
vite-plusindependenciesordevDependenciesgets a directvitedev dependency unless it already declaresvitein a dependency field. - Unrelated selector-shaped and object-valued overrides are preserved.
npm
- Migration normalizes direct aliases before adding the matching override so npm does not fail with
EOVERRIDE. - When changing a real Vite installation to the core alias, remove stale Vite install and lockfile state before reinstalling.
- Add a top-level
viteedge for opt-in browser-provider layouts when nested Vitest packages otherwise cannot resolve it.
Yarn
- Vite+ does not support Plug'n'Play. Detect explicit and implicit PnP before migration and convert the project to
nodeLinker: node-modules. Preserve all unrelated.yarnrc.ymlsettings.--no-interactiveaccepts the conversion; a process-levelYARN_NODE_LINKER=pnpmust be fixed by the caller. - Catalog references and user hoisting settings are preserved.
- Migration avoids split Vitest copies under workspace hoisting isolation. It applies a package-level fix where possible and warns when the isolation cannot be changed safely.
Bun
- Preserve existing top-level or workspace catalog locations and named catalog references.
- Mirror the core alias as a direct
vitedependency so Bun sees the peer provider before applying overrides. - Configure missing-peer suppression in
bunfig.tomlwhen needed, but do not overwrite an explicit userpeersetting.
After updating the manifests and package-manager configuration, migration reinstalls dependencies once to refresh the lockfile. If installation fails, migration reports the error and exits with a nonzero status. After a successful migration, it runs vp fmt unless the project still uses Prettier. A formatter failure is reported as a warning so the migration result and manual formatting command remain available.