Skip to content

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

  1. Run vp upgrade before 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.
  2. Upgrade the project to Vite 8+ and Vitest 4.1+ when necessary.
  3. Run vp migrate from the workspace root. Use --no-interactive in automated environments.
  4. Review every changed manifest, package-manager config, source rewrite, and generated lockfile.
  5. Validate with vp install, vp check, vp test, and vp build.

Running the migration again after a successful migration should not produce another diff.

Dependency Versions

  • vite-plus is pinned to the concrete version of the CLI running the migration, not the latest dist-tag.
  • The vite alias must target @voidzero-dev/vite-plus-core from 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

DependencyMigration rule
vite-plusAdd it where the package is migrated. Re-pin plain ranges to the current concrete target, directly or through a catalog. Preserve deliberate protocol pins.
viteKeep 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.
vitestRemove 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-testRemove 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 vitest peer, whether exact or a range;
  • the package uses Vitest browser mode or an opt-in browser provider;
  • source or TypeScript configuration retains an upstream vitest reference;
  • the package declares @nuxt/test-utils; or
  • dependency metadata is unavailable and an existing direct vitest might 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 vitest to 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 named catalog:<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-plugin has its own version line;
  • @vitest/coverage-c8 stopped 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 vitest and vitest/* imports to vite-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' or declare module '@vitest/browser*'. Module augmentation must retain the upstream module identity.
  • Retained references such as compilerOptions.types, require.resolve, import.meta.resolve, and vitest/package.json require package-local Vitest.
  • In a package that declares @nuxt/test-utils, preserve every vitest and vitest/* module specifier package-wide. Its transform requires the upstream identity and can otherwise inject a duplicate vi import. 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.yaml as the single source for supported root settings. Migration moves recognized package.json#pnpm fields there, including overrides, peer rules, patch settings, package extensions, architecture and build policy, audit/update configuration, and configuration dependencies. It removes the pnpm object 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 and peerDependencyRules required 10.6.2. pnpm 11 no longer reads the legacy package.json settings.
  • Migration keeps dependency references, default and named catalogs, overrides, and peerDependencyRules consistent.
  • Each package that lists vite-plus in dependencies or devDependencies gets a direct vite dev dependency unless it already declares vite in 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 vite edge 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.yml settings. --no-interactive accepts the conversion; a process-level YARN_NODE_LINKER=pnp must 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 vite dependency so Bun sees the peer provider before applying overrides.
  • Configure missing-peer suppression in bunfig.toml when needed, but do not overwrite an explicit user peer setting.

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.