# eslint-plugin-vue: the official linter for Vue single file components

> eslint-plugin-vue is the official ESLint plugin for Vue.js, and it is the only widely used option that understands the template, script and style blocks of a .vue file as one document. This article covers how it parses SFCs, how to install and configure it, and where its versioning policy will bite you.

**vuejs/eslint-plugin-vue** — Official ESLint plugin for Vue.js

- Repository: https://github.com/vuejs/eslint-plugin-vue
- Website: https://eslint.vuejs.org/
- Stars: 4,589 · Forks: 720
- Language: TypeScript
- License: MIT
- Published: 2026-09-23 · Updated: 2026-09-23 · Language: en
- Canonical page: https://hysenlabs.com/projects/vuejs-eslint-plugin-vue

## What eslint-plugin-vue actually lints that plain ESLint cannot

ESLint on its own parses JavaScript. A .vue file is not JavaScript: it is a custom file format with a template block, a script block and optional style blocks, and the default parser will fail on it. The README states that "the default JavaScript parser must be replaced because Vue.js single file components are not plain JavaScript, but a custom file format." That replacement is vue-eslint-parser, which the plugin's documentation points to as the parser to select in AST Explorer alongside the Vue syntax option.

The audience follows from that constraint. If your project is a Vue application with .vue files, this plugin is the only way to get ESLint to see template expressions, directive arguments, component naming and slot usage as lintable code. If your project is plain JavaScript or TypeScript with no SFCs, the plugin adds rules that will never fire. The plugin is maintained under the vuejs organization, published to npm, and licensed MIT, so it is the default answer for Vue teams rather than a third-party alternative.

## How vue-eslint-parser turns a .vue file into a lintable AST

The mechanism is a two-parser arrangement. vue-eslint-parser reads the SFC, splits it into blocks, and produces an enhanced AST whose nodes represent specific parts of the template syntax as well as the contents of the script tag. ESLint's rule engine then walks that AST, but a rule that only knows about script nodes will never see the template. That is why the parser exposes services for rule authors.

The README lists two of them explicitly: context.parserServices.defineTemplateBodyVisitor(visitor, scriptVisitor) and context.parserServices.getTemplateBodyTokenStore(). The first lets a rule register two visitors, one for template nodes and one for script nodes, so a single rule can enforce a convention across both halves of the file. The second gives access to template tokens, which matters for whitespace and spacing rules where you need to inspect raw text rather than node structure. The linked example rule, mustache-interpolation-spacing.js, is where the README points readers who want to see the services in use.

This design is the reason the plugin's rules can be split into template-aware and script-only categories, and it is also the reason a rule written for plain ESLint will not automatically work on templates. If you are writing a custom rule, the README directs you to the ESTree project page and the vue-eslint-parser AST documentation for node shapes, and warns that the RuleTester parser property must be set according to the code samples in your tests.

## Installing eslint-plugin-vue and running it on a first component

The README points to https://eslint.vuejs.org for documentation and does not reproduce install steps inline. What the repository does show is the package name in package.json and a flat config file at the root, eslint.config.mjs, which is the format the plugin's own codebase uses. The README also documents the parser services under the names context.parserServices.defineTemplateBodyVisitor and context.parserServices.getTemplateBodyTokenStore, and names the example rule mustache-interpolation-spacing.js.

Because the README gives no install command, the honest starting point is the official website it links to. What can be confirmed from the repository is the artifact layout: the package.json main field points at dist/index.js and the types field at dist/index.d.ts, with dist listed in the files field, so the published package is the built output rather than the source tree. The build script runs the typegen tool and then tsdown, and tests run through vitest. None of those are consumer-facing commands; they are how the maintainers produce the package.

For a first real use, the constraint to understand is the parser split. A .vue file's script block is JavaScript or TypeScript, and its template is a separate syntax tree. The plugin's rules that touch templates rely on the parser services above, which means a working setup needs vue-eslint-parser in the pipeline, not just the plugin installed next to ESLint. If template rules appear to do nothing, the parser is the first thing to check, because the README's own explanation of why the default parser must be replaced is the same reason template rules go silent without it.

The README does not document editor setup either; it defers to the official website. Since the plugin is an ordinary ESLint plugin, editor integration is a function of how your editor resolves ESLint from the project, not of anything the plugin configures.

## The versioning policy is the real adoption risk

This is the part most teams skim and then regret. The README states that the plugin follows Semantic Versioning but deliberately does not follow ESLint's Semantic Versioning Policy. In minor releases, the plugin may change the sharable configs it provides or the default behavior of its rules in order to add features. The stated reason is that the maintainers want to add features quickly so users can take advantage of new features in Vue and Nuxt.

The consequence is spelled out in the same paragraph: any minor update may report more linting errors than the previous release. A patch-level bump is not the only thing that can turn a green CI run red. The README's own recommendation is to use the tilde (~) in package.json to guarantee the results of your builds, which pins you to patch releases within a minor line.

That is a genuine trade-off, not a flaw. You get rules that track new Vue and Nuxt features faster than a conservative versioning scheme would allow, and you pay for it with a dependency you cannot float. If your team treats lint output as a build gate, the tilde is not optional advice; it is the difference between a predictable pipeline and one that breaks on a routine dependency update. The README does not document a migration guide for config changes between minors, so the practical answer is to read the GitHub Releases page, which the README names as the release channel, before widening the range.

## Where eslint-plugin-vue is the wrong tool

It is not a formatter. ESLint rules can fix whitespace and ordering, but the plugin's job is to flag patterns, and the README makes no formatting claims. Teams that want deterministic styling should pair it with a formatter rather than trying to make lint rules do that work; the search data around this project shows people comparing the two tools, and the comparison is real, not a naming confusion.

It also cannot help with Vue code that never passes through an SFC. A render function in a .ts file, a template string in a build script, or a component defined entirely in JavaScript is parsed as ordinary code, and the template-aware rules have no template to visit. The parser services exist precisely because template nodes are a separate traversal; no template, no traversal.

Finally, the plugin is only as current as its rule coverage for the Vue version you target. The README does not publish a compatibility matrix, and the release notes are the only place version-specific changes appear. If you are on an older Vue line, verify that the preset you select matches it before assuming the recommended set is the right starting point.

## eslint-plugin-vue versus vue-eslint-parser and the config packages

The most common confusion is treating vue-eslint-parser as an alternative. It is not: the parser is the component that makes the plugin possible. The README describes it as the replacement parser that generates the enhanced AST, and the plugin's rules are written against that AST. Installing the plugin without the parser working correctly means rules silently see nothing in templates. They are two layers of one stack, not two choices.

The genuine alternatives are the shared config packages that sit on top of the plugin, such as Vue's TypeScript and Prettier config packages that appear in search data around this project. Those packages bundle the plugin with additional rules and formatter integration. The difference in approach is scope: eslint-plugin-vue gives you the rules and presets, while a config package gives you an opinionated combination of several tools. Choosing the config package means accepting its choices about which plugin rules are on and how they interact with the formatter; choosing the plugin directly means assembling that yourself. Neither is more correct, but the plugin is the layer everything else depends on, so it is the one to understand first.

## Maintenance, licence and what a minor upgrade costs you

The repository is not archived, and the last push was on 2026-09-12. Releases are frequent: v10.11.0 on 2026-09-06, v10.10.0 on 2026-07-20, and v10.9.2 on 2026-06-03. The package.json version matches the newest release, and the build pipeline is visible in the repository: npm run build runs the typegen script and then tsdown, tests run through vitest, and the published artifact is the dist directory listed in the files field. There is a .changeset directory and a changeset publish script, so releases are assembled from changesets rather than hand-cut.

The licence is MIT, stated in the README and present as a LICENSE file at the repository root. MIT is permissive, which matters if you vendor or fork the plugin, but it also means there is no warranty and no support obligation attached. That is a description of the licence text, not advice about your situation.

The upgrade cost is the versioning policy again, expressed as time. Because a minor can change preset contents or rule defaults, an upgrade can surface new errors across a codebase, and each one needs a decision: fix the code or turn the rule off. The README does not describe a deprecation window or a codemod. Budget for reading the release notes and re-running lint before you widen the range in package.json.

## Conclusion

Adopt eslint-plugin-vue if your codebase contains .vue single file components and you already run ESLint; without it, template expressions and directive usage go unchecked by the linter. Do not adopt it as a formatter, and do not expect it to lint Vue code that lives outside SFCs any differently from plain JavaScript. Before rolling it out, verify two things: which flat config preset matches your Vue version, and whether your package.json pins the plugin with a tilde, since the README states that a minor release may report more linting errors than the previous one.

## FAQ

### How do I install eslint-plugin-vue?

The README does not reproduce install steps; it points to the official website at eslint.vuejs.org for documentation. The package is published to npm under the name eslint-plugin-vue.

### What does eslint-plugin-vue do?

It is the official ESLint plugin for Vue.js. It works with vue-eslint-parser to lint the template and script blocks of .vue single file components, which plain ESLint cannot parse.

### Does eslint-plugin-vue work in VS Code?

The plugin is a standard ESLint plugin, so it runs wherever ESLint runs, including the ESLint integration in an editor. The README does not document an editor-specific setup path and points to the official website instead.

### What are the best ESLint plugins to use with Vue?

The README only describes eslint-plugin-vue itself, as the official ESLint plugin for Vue.js, and does not rank other plugins. It does note that the plugin's rules depend on vue-eslint-parser to see template syntax.

### What is the difference between prettier and ESLint?

The README makes no formatting claims for eslint-plugin-vue; its rules flag patterns rather than define a style. Formatting is a separate concern, which is why the plugin is often paired with a formatter rather than used as one.

## Sources

- [License: MIT](https://github.com/vuejs/eslint-plugin-vue/blob/master/LICENSE)
- [Project website](https://eslint.vuejs.org/)
- [README](https://github.com/vuejs/eslint-plugin-vue/blob/master/README.md)
- [Releases](https://github.com/vuejs/eslint-plugin-vue/releases)
- [vuejs/eslint-plugin-vue on GitHub](https://github.com/vuejs/eslint-plugin-vue)

---

Hysen Labs editorial analysis, written from the project's own repository and release notes. Cite the canonical page: https://hysenlabs.com/projects/vuejs-eslint-plugin-vue
