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 (the vue binary, sometimes called "Vue CLI 5") is in maintenance mode. The Vue core team officially recommends create-vue (npm create vue@latest) plus Vite for all new projects. Use @vue/cli only when you maintain an existing project that already depends on it, or when a plugin you require has not been ported to a create-vue + Vite equivalent. Webpack-based @vue/cli projects 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.

bash
npm install -g @vue/cli

Output: added @vue/cli globally; vue on PATH

bash
pnpm add -g @vue/cli

Output: added @vue/cli globally

bash
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:

bash
npx @vue/cli create my-app

Output: runs the scaffolder once.

Recommended modern replacement:

bash
npm create vue@latest my-app

Output: runs the create-vue scaffolder — Vite-based, current.

Verify:

bash
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 / pinia choices 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-vue and the Vite ecosystem instead.

Package metadata

  • Maintainer: Vue.js core team (vuejs/vue-cli monorepo 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):

ToolReplaces
create-vuevue create scaffolder
vite@vue/cli-service (build)
@vitejs/plugin-vuecore Vue SFC handling
vitest@vue/cli-plugin-unit-jest
playwright / cypress@vue/cli-plugin-e2e-*
piniavuex (the previous official store)
vue-router@4vue-router@3 (Vue 2 → Vue 3 migration)
eslint-plugin-vue (direct)@vue/cli-plugin-eslint

Alternatives

ToolWhen to choose it
create-vueRecommended 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 islandVue components inside an Astro static site.
@vue/cliOnly for maintaining an existing app or when a critical plugin lives only here.

Common gotchas

  1. 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 is npm create vue@latest my-app.
  2. vue.config.js ≠ Vite config. Migrating to Vite means deleting vue.config.js and writing vite.config.ts from scratch. The chainable Webpack API doesn't map 1:1.
  3. @vue/cli-service runs 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.
  4. Plugins (@vue/cli-plugin-*) don't have Vite equivalents. Migrating means replacing each one — @vue/cli-plugin-eslint becomes a direct eslint config, @vue/cli-plugin-unit-jest becomes Vitest, etc.
  5. 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, use nvm / fnm to pin Node to the version that worked at the time.
  6. vue ui opens a local web app. It's a graphical project explorer (port 8000 by default). It works only with @vue/cli-scaffolded projects; create-vue projects have no GUI equivalent.
  7. vue add <plugin> modifies your source tree. It runs the plugin's generator which can rewrite package.json, source files, and add new files. Always run on a clean Git working tree so you can review the diff.
  8. Vue 2 end-of-life. If your @vue/cli project 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.

bash
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:

bash
npm create vue@latest my-app

Output: Vite-based project; faster and current.

Scaffold a Vue 2 project (only for migration / legacy)

bash
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-*:

bash
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:

bash
vue add apollo                             # adds @vue/apollo
vue add vuetify                            # adds Vuetify component library

Output: generator runs against your project source.

GUI mode

bash
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

bash
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:

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.

bash
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)
BundlerWebpack 5Vite (Rollup for production)
Dev start5–30 seconds<1 second
HMR500 ms – 2 seconds<50 ms
Config filevue.config.js (Webpack-chain)vite.config.ts (Vite plugins)
Plugin system@vue/cli-plugin-*Vite plugins + per-tool config
GUIvue uinone (use editor integrations)
TypeScriptvia @vue/cli-plugin-typescriptfirst-class
Maintenance statusMaintenance onlyActive development

Production deployment

The "deployment" concern for @vue/cli projects is producing a deployable dist/ directory and shipping it to a host.

Production build

bash
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:

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: false in vue.config.js.
  • Reduce ESLint scope. ESLint plugin runs on every change. Limit lintOnSave to error to skip warnings, or disable in CI with LINT_ON_SAVE=false.
  • Set parallel: true for 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 externals for vue, vue-router, etc., and pull from a CDN in index.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/clicreate-vue + Vite, not between @vue/cli versions.

FromToLikely changes (verify against the changelog)
@vue/cli@3@vue/cli@4Vue 3 support added. Mostly transparent for existing apps.
@vue/cli@4@vue/cli@5Webpack 5 (was Webpack 4). Some plugin APIs changed. Node 12 floor.
@vue/cli@5create-vue + ViteRecommended path. See migration guide on vuejs.org.

Migration steps to Vite (high-level)

  1. npm create vue@latest my-app-vite in a sibling directory. Pick the same options (TypeScript, Router, Pinia, ESLint).
  2. Copy src/, public/, index.html (with adjustments) from the old project.
  3. Replace Webpack-chain customisations in vue.config.js with Vite plugins / vite.config.ts settings.
  4. Replace @vue/cli-plugin-* deps with their Vite-ecosystem equivalents (see the table above).
  5. Update package.json scripts: "dev": "vite", "build": "vue-tsc -b && vite build", "preview": "vite preview".
  6. Run npm test / npm run build and fix the inevitable import-path issues — Vite is stricter about extensions and aliases.
  7. 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:

ConcernPattern
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 importsWebpack handles .vue files via vue-loader. ESM/CJS irrelevant for app code.
CommonJS depsWebpack inlines them. No special config needed.
Pure-ESM depsSome 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:

PluginReplaces in modern Vite setup
@vue/cli-plugin-babel(handled by Vite/esbuild)
@vue/cli-plugin-typescriptvue-tsc + Vite
@vue/cli-plugin-eslinteslint + eslint-plugin-vue directly
@vue/cli-plugin-pwavite-plugin-pwa
@vue/cli-plugin-routervue-router (no plugin needed)
@vue/cli-plugin-vuexpinia (Vuex deprecated)
@vue/cli-plugin-unit-jestvitest
@vue/cli-plugin-unit-mochavitest
@vue/cli-plugin-e2e-cypresscypress directly
@vue/cli-plugin-e2e-nightwatchplaywright (preferred)
@vue/cli-servicevite

Testing & CI integration

Tests run via whichever plugin was installed (Jest, Mocha, Cypress, Nightwatch). The CI pattern:

yaml
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 audit regularly flags issues that can't be fixed without breaking the project.
  • vue add runs arbitrary code. Plugin generators are unsandboxed npm packages. Audit the plugin source before running on a sensitive codebase.
  • vue ui exposes a local web server. Port 8000 by default. Don't run on a multi-user machine.
  • publicPath mis-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 memoryNODE_OPTIONS=--max-old-space-size=4096 (or 8192) before the build script.

Plugin generator wrote bad configgit 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 (the create-vue scaffold + 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-tsc is 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/cli doesn'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