cheat sheet
@vue/cli
Reference for the legacy @vue/cli npm package — install, command surface, plugin model, and why create-vue + Vite is the recommended path for new projects.
@vue/cli
Deprecation banner — read this first.
@vue/cli(thevuebinary, sometimes called "Vue CLI 5") is in maintenance mode. The Vue core team officially recommendscreate-vue(npm create vue@latest) plus Vite for all new projects. Use@vue/clionly when you maintain an existing project that already depends on it, or when a plugin you require has not been ported to acreate-vue+ Vite equivalent. Webpack-based@vue/cliprojects still receive security fixes, but no new features. This article exists as a reference, not a recommendation.
What it is
@vue/cli is the historical CLI for scaffolding, developing, and building Vue.js applications. It wraps Webpack with sensible defaults, provides a plugin system (@vue/cli-plugin-*), a graphical UI (vue ui), and a long-standing project preset model. It supported both Vue 2 and Vue 3 in the same toolchain and was the de-facto starting point for Vue apps from 2017 through ~2022.
The Vue ecosystem has moved to Vite-first tooling. create-vue is the official scaffold; it produces a Vite-based project. For new Vue 3 work, create-vue is faster (Vite's dev server starts in milliseconds vs @vue/cli's 5–30 seconds for non-trivial projects), uses a smaller / simpler config, and tracks the rest of the modern frontend stack.
Reach for @vue/cli only to maintain a legacy app, or in narrow cases where a custom Webpack config / @vue/cli-plugin-* is the simplest path. New project? Use create-vue instead.
Install
The CLI is published as @vue/cli. The vue binary becomes available on PATH.
npm install -g @vue/cli
Output: added @vue/cli globally; vue on PATH
pnpm add -g @vue/cli
Output: added @vue/cli globally
yarn global add @vue/cli
Output: added @vue/cli globally
Per-project install is uncommon — @vue/cli is almost always used globally for scaffolding, with the per-project tooling installed as the project's own dev deps.
For one-off use without installing:
npx @vue/cli create my-app
Output: runs the scaffolder once.
Recommended modern replacement:
npm create vue@latest my-app
Output: runs the create-vue scaffolder — Vite-based, current.
Verify:
vue --version
Output: prints CLI version (currently the 5.x line; no 6.x is planned).
Versioning & Node support
Current line is @vue/cli@5.x. There is no planned 6.x — the project is in maintenance.
- Node 14+ supported. Node 18 and 20 work but the underlying Webpack 5 + assorted plugins haven't been tested against Node 22+ comprehensively.
- The CLI itself is CJS, written before the ESM transition swept the ecosystem.
- Vue 2 and Vue 3 both supported via the
vue-router,vuex/piniachoices in the scaffolder. Vue 2 itself reached end-of-life in late 2023; only continue if you're on the paid support tier. - Patch releases continue rarely (security fixes). New features land in
create-vueand the Vite ecosystem instead.
Package metadata
- Maintainer: Vue.js core team (
vuejs/vue-climonorepo on GitHub; archived activity) - Project home: github.com/vuejs/vue-cli
- Migration guide: vuejs.org/guide/scaling-up/tooling
- npm: npmjs.com/package/@vue/cli
- License: MIT
- First released: 2017 (CLI 3.x was the redesign that introduced the plugin system)
- Downloads: ~50–100k weekly — declining as projects migrate to Vite/create-vue.
Peer dependencies & extras
@vue/cli itself has minimal peer deps but installs a deep tree of @vue/cli-service, Webpack 5, Babel, PostCSS, and assorted loaders.
Companion / plugin packages (legacy):
@vue/cli-service— the actual build runner; installed per-project as a devDep@vue/cli-plugin-babel,@vue/cli-plugin-typescript,@vue/cli-plugin-eslint,@vue/cli-plugin-router,@vue/cli-plugin-vuex,@vue/cli-plugin-pwa,@vue/cli-plugin-e2e-cypress,@vue/cli-plugin-unit-jest, etc.@vue/cli-ui— the GUI (vue ui)
Modern Vue toolchain (recommended):
| Tool | Replaces |
|---|---|
create-vue | vue create scaffolder |
vite | @vue/cli-service (build) |
@vitejs/plugin-vue | core Vue SFC handling |
vitest | @vue/cli-plugin-unit-jest |
playwright / cypress | @vue/cli-plugin-e2e-* |
pinia | vuex (the previous official store) |
vue-router@4 | vue-router@3 (Vue 2 → Vue 3 migration) |
eslint-plugin-vue (direct) | @vue/cli-plugin-eslint |
Alternatives
| Tool | When to choose it |
|---|---|
create-vue | Recommended for any new Vue 3 project. npm create vue@latest. Vite-based, current, maintained. |
vite (direct) | Maximum control. npm create vite@latest -- --template vue-ts. |
nuxt (create-nuxt-app) | Full Vue meta-framework (SSR, routing, SEO). |
quasar (@quasar/cli) | Quasar Framework — Vue-based, broader component library + multi-target builds. |
astro + Vue island | Vue components inside an Astro static site. |
@vue/cli | Only for maintaining an existing app or when a critical plugin lives only here. |
Common gotchas
- You picked a deprecated tool by accident. Many beginner tutorials still say
vue create my-app. They're outdated — check the publication date. The modern command isnpm create vue@latest my-app. vue.config.js≠ Vite config. Migrating to Vite means deletingvue.config.jsand writingvite.config.tsfrom scratch. The chainable Webpack API doesn't map 1:1.@vue/cli-serviceruns Webpack 5. Build times grow with the codebase. A 200-component app may take 30–60 seconds for dev start and 1–3 minutes for production build. Vite handles the same in 1–5 seconds dev start.- Plugins (
@vue/cli-plugin-*) don't have Vite equivalents. Migrating means replacing each one —@vue/cli-plugin-eslintbecomes a directeslintconfig,@vue/cli-plugin-unit-jestbecomes Vitest, etc. - Node version mismatch breaks the install silently. Older
@vue/cli(3.x, 4.x) doesn't work on Node 18+. If you're maintaining a legacy project, usenvm/fnmto pin Node to the version that worked at the time. vue uiopens a local web app. It's a graphical project explorer (port 8000 by default). It works only with@vue/cli-scaffolded projects;create-vueprojects have no GUI equivalent.vue add <plugin>modifies your source tree. It runs the plugin's generator which can rewritepackage.json, source files, and add new files. Always run on a clean Git working tree so you can review the diff.- Vue 2 end-of-life. If your
@vue/cliproject still runs Vue 2, you're on EOL software. Either pay for Vue 2 Extended LTS (HeroDevs) or migrate to Vue 3 + create-vue.
Real-world recipes
These recipes target the legacy maintenance use case. For new projects, see the create-vue / Vite migration recipes below.
Scaffold a Vue 3 project (legacy method, NOT recommended)
vue create my-app
Output: interactive prompt for preset (Default, Manual, …). Choose Manual to pick Vue 3, TypeScript, Router, Pinia/Vuex, ESLint, Unit testing.
The output is a Webpack-based project at my-app/. Modern equivalent:
npm create vue@latest my-app
Output: Vite-based project; faster and current.
Scaffold a Vue 2 project (only for migration / legacy)
vue create my-app --preset default
Output: scaffolds with the default preset (Vue 2 if you preserved the legacy config). Verify with cat package.json | grep '"vue":'.
For Vue 2 with the modern toolchain (Vite + Vue 2.7), use create-vue with the Vue 2 community templates instead.
Add a plugin to an existing @vue/cli project
vue add installs and runs a generator for a @vue/cli-plugin-*:
vue add @vue/typescript # adds TypeScript support
vue add @vue/eslint # adds ESLint
vue add @vue/pwa # adds Progressive Web App config
vue add router # vue-router
vue add vuex # vuex (deprecated; prefer Pinia)
Output: modifies package.json deps and runs the plugin's generator (rewrites entrypoints, adds config). Review the Git diff before committing.
For non-@vue/-namespaced plugins, the full package name is needed:
vue add apollo # adds @vue/apollo
vue add vuetify # adds Vuetify component library
Output: generator runs against your project source.
GUI mode
vue ui
Output: opens http://localhost:8000 with the project dashboard, plugin browser, and task runner. Useful for tutorials and demos; superseded by editor integrations for daily work.
Inspect the resolved Webpack config
vue inspect > webpack.resolved.js
vue inspect --rule vue
vue inspect --plugin html
Output: prints the full resolved Webpack config — useful for debugging plugin interactions or for "ejecting" mental model.
Ejected Webpack config
Older Vue CLI 2 had an eject command. @vue/cli@3+ has no eject command — you customise via vue.config.js:
// vue.config.js
module.exports = {
publicPath: process.env.NODE_ENV === "production" ? "/my-app/" : "/",
configureWebpack: {
resolve: {
alias: { "@components": "src/components" },
},
},
chainWebpack: (config) => {
config.module
.rule("vue")
.use("vue-loader")
.tap((options) => ({ ...options, compatConfig: { MODE: 2 } }));
},
};
The chainWebpack API is @vue/cli-specific (uses webpack-chain). It does NOT exist in Vite.
Compare with create-vue (the recommended modern path)
npm create vue@latest my-app
Output: interactive prompt — TypeScript? Router? Pinia? ESLint? Prettier? Playwright? Vitest? Each yes adds the dep + config. The resulting project uses Vite, has no vue.config.js, and starts the dev server in <1 second.
| Aspect | @vue/cli (legacy) | create-vue + Vite (current) |
|---|---|---|
| Bundler | Webpack 5 | Vite (Rollup for production) |
| Dev start | 5–30 seconds | <1 second |
| HMR | 500 ms – 2 seconds | <50 ms |
| Config file | vue.config.js (Webpack-chain) | vite.config.ts (Vite plugins) |
| Plugin system | @vue/cli-plugin-* | Vite plugins + per-tool config |
| GUI | vue ui | none (use editor integrations) |
| TypeScript | via @vue/cli-plugin-typescript | first-class |
| Maintenance status | Maintenance only | Active development |
Production deployment
The "deployment" concern for @vue/cli projects is producing a deployable dist/ directory and shipping it to a host.
Production build
npm run build
Output: generates dist/ with hashed assets ready for static hosting. Build artifacts include index.html, JS/CSS chunks, source maps (unless disabled), and any static assets from public/.
Deploy targets
Static dist/ works anywhere — Cloudflare Pages, Vercel, Netlify, Nginx, S3 + CloudFront, GitHub Pages. No platform-specific adapter needed because Vue CLI produces a plain SPA.
For SPA deep-link routing (Vue Router in history mode), configure the host to fallback to index.html for all unknown paths. Example for Cloudflare Pages: add _redirects with /* /index.html 200.
publicPath for sub-path hosting
When deploying to a sub-path (e.g. example.com/my-app/), set publicPath in vue.config.js:
module.exports = {
publicPath: process.env.NODE_ENV === "production" ? "/my-app/" : "/",
};
Forgetting this breaks all hashed asset URLs in production.
Performance tuning
@vue/cli builds are Webpack 5 builds. Performance work is generic Webpack tuning, but the most common levers:
- Disable source maps in prod to halve build time:
productionSourceMap: falseinvue.config.js. - Reduce ESLint scope. ESLint plugin runs on every change. Limit
lintOnSavetoerrorto skip warnings, or disable in CI withLINT_ON_SAVE=false. - Set
parallel: truefor Babel/Terser. Default in@vue/cli@5, but verify. - Code-split aggressively. Dynamic
import()for route components — the router-async-component pattern. - Move heavy deps to CDN. Configure Webpack
externalsforvue,vue-router, etc., and pull from a CDN inindex.html. - For real performance gains, migrate to Vite. Vite's dev-server speedup is 10–100×; production build via Rollup is often faster too.
Version migration guide
The most important migration is @vue/cli → create-vue + Vite, not between @vue/cli versions.
| From | To | Likely changes (verify against the changelog) |
|---|---|---|
@vue/cli@3 | @vue/cli@4 | Vue 3 support added. Mostly transparent for existing apps. |
@vue/cli@4 | @vue/cli@5 | Webpack 5 (was Webpack 4). Some plugin APIs changed. Node 12 floor. |
@vue/cli@5 | create-vue + Vite | Recommended path. See migration guide on vuejs.org. |
Migration steps to Vite (high-level)
npm create vue@latest my-app-vitein a sibling directory. Pick the same options (TypeScript, Router, Pinia, ESLint).- Copy
src/,public/,index.html(with adjustments) from the old project. - Replace Webpack-chain customisations in
vue.config.jswith Vite plugins /vite.config.tssettings. - Replace
@vue/cli-plugin-*deps with their Vite-ecosystem equivalents (see the table above). - Update
package.jsonscripts:"dev": "vite","build": "vue-tsc -b && vite build","preview": "vite preview". - Run
npm test/npm run buildand fix the inevitable import-path issues — Vite is stricter about extensions and aliases. - Migrate one route / feature at a time if the codebase is large.
The Vue documentation has a detailed migration guide at vuejs.org/guide/scaling-up/tooling.
ESM/CJS interop & bundling
@vue/cli is CJS internally. The user-facing concern is the project's own ESM/CJS posture:
| Concern | Pattern |
|---|---|
package.json "type" | Default "commonjs" for @vue/cli projects. Override to "module" only if you understand the cascading effects on Webpack config files. |
| Vue SFC imports | Webpack handles .vue files via vue-loader. ESM/CJS irrelevant for app code. |
| CommonJS deps | Webpack inlines them. No special config needed. |
| Pure-ESM deps | Some newer deps (e.g. chalk@5+, node-fetch@3+) are ESM-only and incompatible with Webpack 5's default CJS loader chain. Workaround: pin to older CJS-compatible versions, or transpile via Babel. This is the most frequent legacy pain point. |
Plugin & ecosystem coverage
The legacy plugin catalog is rich but frozen:
| Plugin | Replaces in modern Vite setup |
|---|---|
@vue/cli-plugin-babel | (handled by Vite/esbuild) |
@vue/cli-plugin-typescript | vue-tsc + Vite |
@vue/cli-plugin-eslint | eslint + eslint-plugin-vue directly |
@vue/cli-plugin-pwa | vite-plugin-pwa |
@vue/cli-plugin-router | vue-router (no plugin needed) |
@vue/cli-plugin-vuex | pinia (Vuex deprecated) |
@vue/cli-plugin-unit-jest | vitest |
@vue/cli-plugin-unit-mocha | vitest |
@vue/cli-plugin-e2e-cypress | cypress directly |
@vue/cli-plugin-e2e-nightwatch | playwright (preferred) |
@vue/cli-service | vite |
Testing & CI integration
Tests run via whichever plugin was installed (Jest, Mocha, Cypress, Nightwatch). The CI pattern:
jobs:
test-and-build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with: { node-version: 18 }
- run: npm ci
- run: npm run lint
- run: npm run test:unit
- run: npm run build
The CI runs are slow compared to Vite-based projects (Webpack build dominates wall time). One more reason to migrate.
Security considerations
- Transitive deps in maintenance-mode tools accumulate CVEs. Webpack 5 + Babel + assorted loaders have a large attack surface.
npm auditregularly flags issues that can't be fixed without breaking the project. vue addruns arbitrary code. Plugin generators are unsandboxed npm packages. Audit the plugin source before running on a sensitive codebase.vue uiexposes a local web server. Port 8000 by default. Don't run on a multi-user machine.publicPathmis-configuration leaks file paths. A misconfigured base path can make source-map URLs leak into production HTML.- Migrate proactively, not after a CVE. The longer a project stays on
@vue/cli, the more painful the migration. Schedule the Vite migration before it becomes urgent.
Troubleshooting common errors
command not found: vue — @vue/cli not installed globally, or PATH doesn't include the npm global bin. npm install -g @vue/cli and verify with npm bin -g.
Module build failed: Error: ERR_OSSL_EVP_UNSUPPORTED — Node 17+ default to OpenSSL 3, breaking Webpack 4's legacy MD4 usage. Add NODE_OPTIONS=--openssl-legacy-provider to your scripts, OR upgrade to @vue/cli@5 (Webpack 5).
vue-loader errors after a dep bump — Webpack 4 vs Webpack 5 incompatibility. Check the dep's peerDeps; most recent loaders require Webpack 5.
ERR_REQUIRE_ESM — a transitive dep went ESM-only. Pin the dep to its last CJS version, or migrate to Vite.
vue create hangs on dep install — npm registry slow or offline. Cancel and retry. Use a local mirror via .npmrc if behind a corporate proxy.
Routes 404 in production — SPA history-mode without server-side fallback. Configure host to serve index.html for unknown paths.
Build runs out of memory — NODE_OPTIONS=--max-old-space-size=4096 (or 8192) before the build script.
Plugin generator wrote bad config — git diff to see what was added; revert and configure manually.
When NOT to use this
@vue/cli is the wrong default. Skip it when:
- You're starting a new Vue project. Use
npm create vue@latest(thecreate-vuescaffold + Vite). The Vue core team's recommendation. - You want fast dev iteration. Vite is 10–100× faster than
@vue/cli's Webpack dev server. - You need first-class TypeScript.
create-vue+vue-tscis a smoother path. - You're targeting SSR, SSG, or edge runtimes. Use Nuxt or Vike, not
@vue/cli. - You're building a component library. Vite has a dedicated library mode (
build.lib).@vue/clidoesn't. - You need an SSR framework. Nuxt (Vue 3) is the answer, not
@vue/cli.
Use @vue/cli only when:
- Maintaining a legacy app with significant
vue.config.js/@vue/cli-plugin-*integration. - Required by a plugin or internal tool that has no Vite equivalent.
- Bound by team / org policy to a frozen toolchain.
In all other cases, the recommended migration target is create-vue + Vite.
See also
- JavaScript: vue-cli — full CLI reference, command surface, migration tips
- JavaScript: vite — the modern Vue build tool
- Packages-npm: vite — package-level reference for Vite
- Concept: api — npm registry HTTP API used by the scaffolder