@remylagerweij/vue-doctor
| Install | |
|---|---|
npm install @remylagerweij/vue-doctor |
|
| Latest Version: | 2.0.2 |
| Vue: | 3 |
| License: | MIT |
| Last Updated: | Oct 19, 2026 |
| Links: | GitHub · npm |
Vue Doctor 🩺
Diagnose and fix performance issues in your Vue.js app. Get a 0–100 health score with actionable recommendations.
Quick Start
npx vue-doctor@latest
What It Checks
Vue Doctor runs three parallel analysis passes on your codebase:
1. Oxlint + Vue Doctor Plugin (59 rules, 54 on by default)
Custom ESTree-based rules for Vue.js:
| Category | Rules | Examples |
|---|---|---|
| Reactivity | 9 | no-fetch-in-watch, no-watch-for-computed, prefer-computed |
| Ecosystem | 4 | pinia-no-destructure, router-no-string-push |
| Architecture | 2 | no-giant-component, no-nested-component-definition |
| Performance | 18 | no-transition-all, no-layout-property-animation, async-parallel |
| Security | 3 | no-secrets-in-client-code, no-unsafe-html-sink |
| Bundle Size | 5 | no-full-lodash-import, no-moment, prefer-dynamic-import |
| Correctness | 8 | no-array-index-as-key, no-prevent-default, no-direct-dom-manipulation |
| Nuxt | 9 | nuxt-no-img-element, nuxt-no-a-element, nuxt-async-client-component |
| Server | 1 | server-no-console-in-handler |
| Supply Chain | 3 | lockfile-integrity, no-remote-dependency-spec, no-dependency-install-scripts (project checks) |
2. ESLint Plugin Vue (20 template rules)
Template-level analysis with eslint-plugin-vue:
vue/require-v-for-key,vue/no-use-v-if-with-v-forvue/no-mutating-props,vue/no-ref-as-operandvue/no-side-effects-in-computed-propertiesvue/component-name-in-template-casing- And more...
3. Dead Code Detection
Powered by Knip:
- Unused files, exports, types, dependencies
Usage
# Scan current directory
vue-doctor
# Scan a specific project
vue-doctor --project ./my-vue-app
# Score only (for CI)
vue-doctor --score
# Verbose output with file details
vue-doctor --verbose
# Only lint checks (skip dead code)
vue-doctor --no-dead-code
# Only dead code checks (skip lint)
vue-doctor --no-lint
# Scan only changed files (diff mode)
vue-doctor --diff main
Configuration
Put one config file in the project root: vue-doctor.config.ts (or .mts, .js, .mjs, .json), or a vueDoctor key in package.json. Parent directories are never searched.
// vue-doctor.config.ts
import { defineConfig } from "@remylagerweij/vue-doctor";
export default defineConfig({
extends: ["vue-doctor/recommended"], // or "vue-doctor/strict", "vue-doctor/security"
rules: {
"no-giant-component": "off",
"vue-doctor/security/no-unsafe-html-sink": "error",
},
ignore: { files: ["src/legacy/**"], rules: ["no-prevent-default"] },
gate: { failOn: "error", scope: "new", minScore: 70 },
deadCode: true,
});
{
"$schema": "./node_modules/@remylagerweij/vue-doctor/schema/vue-doctor.schema.json",
"ignore": { "files": ["src/legacy/**"] }
}
rulessets a severity ("off","warn","error") per rule. Rule IDs arevue-doctor/<category>/<rule>(e.g.vue-doctor/bundle-size/no-moment),vue/<rule>for template rules andknip/<type>;vue-doctor/security/*selects a whole group. The 1.x formsno-momentandvue-doctor/no-momentstill work but print a deprecation warning.gate,lint,deadCode,verboseanddiffare defaults; command-line flags win.- The config is validated: unknown keys and invalid values exit with code 2 and say what is wrong.
.ts/.jsconfigs are executed. Use JSON when scanning untrusted code.
Baseline
Adopting Vue Doctor on an existing codebase? Record today's findings and only fail on new ones:
npx @remylagerweij/vue-doctor baseline # writes .vue-doctor-baseline.json (commit it)
npx @remylagerweij/vue-doctor --baseline .vue-doctor-baseline.json --gate new --fail-on error
Set "baseline": ".vue-doctor-baseline.json" in the config to apply it by default. Fingerprints survive code moving within a file.
Suppressing Findings
Vue Doctor has its own suppression comments. eslint-disable / oxlint-disable comments do not hide Vue Doctor findings, and Vue Doctor never modifies your files.
// vue-doctor-disable-next-line vue-doctor/bundle-size/no-moment -- legacy report page
import moment from "moment";
const html = render(); // vue-doctor-disable-line
/* vue-doctor-disable vue-doctor/bundle-size/no-moment */ /* vue-doctor-enable vue-doctor/bundle-size/no-moment */
// vue-doctor-disable-file no-giant-component
In .vue templates use HTML comments: <!-- vue-doctor-disable-next-line vue-doctor/security/no-unsafe-html-sink -->. Without a rule list every rule is suppressed; rules are written as canonical IDs (vue-doctor/<category>/<rule>, vue/<rule>); the 1.x forms rule and vue-doctor/rule still work with a deprecation warning.
Programmatic API
import { diagnose } from "vue-doctor/api";
const result = await diagnose({
directory: "./my-vue-app",
lint: true,
deadCode: true,
verbose: false,
});
console.log(result.scoreResult?.score); // 0–100
console.log(result.diagnostics.length); // number of issues
GitHub Action
- uses: remylagerweij/vue-doctor@v1
with:
directory: "."
Framework Support
- Vue 3 (Composition API,
<script setup>) - Nuxt 3 (auto-detected, enables Nuxt-specific rules)
- Vite / Quasar / Vue CLI
- Monorepo workspaces (npm, pnpm, yarn)
License
MIT
Related Packages
Nuxt.js module to automatically make your webpack builds faster and smaller.
Version History
| Version | Released | License |
|---|---|---|
| 2.0.2 | MIT | |
| 2.0.1 | MIT | |
| 2.0.0 | MIT | |
| 1.1.2 | MIT | |
| 1.1.1 | MIT | |
| 1.1.0 | MIT | |
| 1.0.1 | MIT | |
| 1.0.0 | MIT |