How to Migrate an Existing Project to Vite+
Migrate an existing project to Vite+ with vp migrate. Check prerequisites, review converted configs and hooks, verify builds and tests, and update CI safely.
To migrate an existing project to Vite+, run vp migrate at the project or workspace root on a fresh branch. Read the plan it prints before any files change, then confirm the result with vp install, vp check, vp test and vp build (or vp pack for a library) before you update CI.
Moving a working repo with five separate tool configs onto a new toolchain is the kind of change that looks small in a PR title and then takes up a full sprint. Usually the trouble starts once the automated part has finished, in what it did and didn’t convert.
This guide is for projects that already run Vite, Vitest, ESLint and Prettier. It covers what vp migrate changes, what it leaves for you, what to check afterwards, and how to update GitHub Actions and GitLab CI. If you need an overview of Vite+ and its commands first, start with Getting Started with Vite+. Vite+ 1.0 shipped on 28 September 2026 under the MIT license.
Key Takeaways
- Projects not yet on Vite+ need Vite 7+ and Vitest 4+ before running
vp migrate, and the Vite+ CLI requires Node.js^22.18.0 || ^24.11.0 || >=26.0.0. - In a monorepo, run
vp migrateonce at the workspace root, because lockfiles, catalogs and package-manager settings are shared across packages. vp migrateleaves Husky, lefthook, simple-git-hooks and yorkie in place and prints a warning instead of converting them.- On GitHub Actions, a single
voidzero-dev/setup-vpstep withnode-versionandcache: truereplaces separate Node, package-manager, install and cache steps. - Pin setup-vp to an exact release tag or commit SHA, because the floating
v1tag no longer receives updates.
Who Should Migrate to Vite+ and What Do You Get?
Migrating suits teams that maintain separate configs for Vite, Vitest, ESLint, Prettier and a library bundler such as tsup or tsdown. After migration you have one vite-plus dependency and one vite.config.ts that holds dev, test, lint, format and pack settings. tsup is a supported migration source, so a TypeScript library that bundles with tsup can come across too. Expect follow-up work, though. The migration guide states plainly that most projects need some manual adjustment once the command finishes.
What Do You Need Before Running vp migrate?
Run the Vite+ migration on its own branch, starting from a clean working tree. That way the diff contains only migration changes and is easy to throw away.
git switch -c chore/migrate-vite-plus
git status # should report a clean tree
Check these three things before you start:
- Vite 7 or later. Older projects need to upgrade Vite first. What’s New in Vite 7 covers the changes in that release.
- Vitest 4 or later. Upgrade older suites to v4 before migrating.
- Node.js
^22.18.0 || ^24.11.0 || >=26.0.0, per the Vitest 5 upgrade guide.
Do any upstream upgrades first and validate them, then keep the existing lockfile and installed packages. The migrator reads them to work out which Vitest version you started from.
Run vp migrate and Read the Plan
Running vp migrate with no arguments migrates the current directory. It shows the planned changes before it writes any files. Pass a path to migrate a project in another directory.
vp migrate # interactive, migrates the current directory
vp migrate ./path/to/project # migrate another directory
vp migrate --no-interactive # scripted runs
The migrate command accepts these flags:
--no-interactiveruns without prompts.--agent <name>/--no-agentcontrols whether coding-agent instruction files are set up.--editor <name>/--no-editorcontrols whether editor configuration is written.--hooks/--no-hookscontrols whether git hooks are set up.
In a monorepo, the workspace root is the only valid target for vp migrate. The lockfiles, catalogs and package-manager settings it rewrites belong to every package in the workspace, so run it once from the root. Don’t run it package by package.
What Does vp migrate Convert and What Does It Leave Alone?
vp migrate updates dependencies, rewrites imports, merges tool configuration into vite.config.ts, updates package.json scripts and formats the files it changed. It deliberately leaves existing git-hook tools untouched.
| Item | What happens |
|---|---|
| Dependencies, imports, scripts | Converted |
| Oxlint, Oxfmt and JSON lint-staged config | Merged into vite.config.ts |
| tsdown config | Brought into the pack block of vite.config.ts |
| ESLint flat config, Prettier config | Converted to Oxlint/Oxfmt settings and merged; old packages, configs and scripts are replaced |
Legacy .eslintrc | Left in place, along with ESLint and its lint script |
| lint-staged (JSON config) | Moved to a staged block if no hook tool is kept |
Non-JSON .lintstagedrc, lint-staged.config.* | Not migrated automatically |
| Husky | Left as-is, with a warning |
| lefthook, simple-git-hooks, yorkie | Left as-is, with a warning, even when you pass --hooks |
declare module 'vitest' | Left as-is on purpose |
Test imports switch from upstream Vitest to the re-exports in vite-plus, which bundles Vitest 5. Type augmentations still target upstream vitest:
// before
import { defineConfig } from 'vitest/config'
import { describe, it, expect } from 'vitest'
// after
import { defineConfig } from 'vite-plus'
import { describe, it, expect } from 'vite-plus/test'
declare module 'vitest' {
// unchanged: augmentations keep targeting upstream vitest
}
If you keep a hook tool, lint-staged stays too, because vp staged reads only the staged block in vite.config.ts. You switch to it by hand:
import { defineConfig } from 'vite-plus'
export default defineConfig({
staged: {
'*.{js,ts,tsx}': 'vp check --fix',
},
})
For libraries on tsdown older than 0.23 (or when the installed version can’t be found), the migration keeps the old defaults. It adds deps.resolveDepSubpath: true to the pack block if you haven’t set it, and adds attw.profile: 'strict' if ATTW checks are on and no profile is set. The migration rules list the full set of transformations.
How Do You Verify the Migrated Project?
Run vp install, vp check, vp test and vp build (or vp pack for a library), and review each result before you commit. Because the migration runs the formatter over the files it changed, review the formatting changes separately from the dependency, config and import changes. Otherwise a reformatting diff can hide logic changes.
| Command | What to inspect |
|---|---|
vp install | Lockfile changes |
vp check | New lint and format findings |
vp test | Test results; for v4 configs, the compatibility settings added for options you hadn’t set |
vp build / vp pack | Output files; for libraries, emitted imports, declarations and the tsdown compatibility settings |
Read the review report the migration writes before you commit. If you run browser-mode, coverage or benchmark suites, run them separately as well.
What If Lint or Format Rules Don’t Carry Over?
The migration converts ESLint flat config to Oxlint and Prettier config to Oxfmt where it can, but not every ESLint rule has an Oxlint equivalent. vp migrate lists the unsupported rules it skips. If a rule you depend on doesn’t come across, keep the original tool as a project script and run it through vp run:
{ "scripts": { "lint:eslint": "eslint ." } }
vp run lint:eslint
This only works if the ESLint script survives the migration. That happens if you declined the ESLint/Prettier conversion prompt or have a legacy .eslintrc. Otherwise, add the package, config and script back yourself after migrating. Note that vp test always runs the built-in test command, while vp run test runs whatever test script is in package.json.
If Node or the package manager resolves to the wrong version, run vp env doctor to diagnose it.
How Do You Update CI for Vite+?
In CI, the Vite+ setup action replaces the separate Node, package manager, install and cache steps, and the jobs call the vp commands directly. On GitHub Actions, setup-vp installs dependencies unless you set run-install: false:
name: CI
on:
push:
branches: [main]
pull_request:
jobs:
check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v7
- uses: voidzero-dev/setup-vp@<setup-vp-version>
with:
node-version: '24'
cache: true
- run: vp check
- run: vp test
- run: vp build
On GitLab, the CI guide has you include the remote setup-vp.yml template, extend .setup-vp and use an image that already contains Node:
include:
# copy the exact remote URL from the Vite+ CI guide
- remote: 'https://raw.githubusercontent.com/voidzero-dev/setup-vp/<setup-vp-version>/gitlab/setup-vp.yml'
inputs:
setup-ref: '<setup-vp-version>'
check:
extends: .setup-vp
image: node:24
# caching uses GitLab's native cache: keyword
script:
- vp check
- vp test
- vp build
Pin setup-vp to an exact release tag or commit SHA rather than v1, because VoidZero no longer updates that tag. Search your workflows for setup-vp@v1 and replace it. On GitLab, the version appears twice (once in the include URL and once in setup-ref), and you need to update both by hand when you upgrade.
Conclusion
A Vite+ migration goes smoothly when you treat vp migrate as the first step rather than the whole job. Read its plan, keep formatting changes apart from logic changes, run the four verification commands, and pin setup-vp in CI before you merge. Next, open the branch, run vp migrate, and go through the warnings it prints for hooks and lint rules.
FAQs
What does vp migrate do on a project that already uses Vite+?
It only upgrades the toolchain. It updates dependencies and package-manager settings across every workspace package to the versions bundled with the CLI running the migration, and finalizes imports. It skips first-time setup such as git hooks, editor and agent files, and lint migration. Pass --full to also run those setup actions. Run vp upgrade first so the global CLI has the latest migration rules.
Should I run vp migrate from the project's own node_modules?
No. The Vite+ migration guide says not to run migration with an old project's node_modules/.bin/vp. Use a global vp, or fetch the target release with npx --package=vite-plus@version vp migrate or the pnpm dlx equivalent. This loads the target CLI without replacing the project's old dependencies first, so the migrator can still detect which Vitest version you started from.
Which package managers does Vite+ support after migration?
Vite+ works with pnpm, npm, Yarn and Bun. It detects the package manager from files at the workspace root, such as the packageManager field and the lockfile, and falls back to pnpm if it finds none. vp install then runs the matching install behaviour for the detected manager, including the correct lockfile flags.
How do I find out which ESLint rules the migration dropped?
vp migrate reports the unsupported ESLint rules it skips during conversion to Oxlint. This arrived in Vite+ 0.3.2 so you can review the checks you lose. Go through that list before you commit, then re-add any rules you need by keeping ESLint as a project script and running it through vp run.
Gain Debugging Superpowers
Unleash the power of session replay to reproduce bugs, track slowdowns and uncover frustrations in your app. Get complete visibility into your frontend with OpenReplay — the most advanced open-source session replay tool for developers.
Star on GitHub12k