Open-source project
stylelint/stylelint avatar
stylelint/stylelint

stylelint: a CSS linter with a plugin API and a very opinionated release cadence

A mighty CSS linter that helps you avoid errors and enforce conventions.

11,526 stars1,025 forksJavaScriptMIT

At a glance

What is it?
Over a hundred built-in rules, autofix on many of them, custom syntaxes for preprocessors, and a release history that reads like a list of false positives being closed one at a time.
Who is it for?
stylelint is at its best on plain CSS, where the built-in rule set is deep and the autofix paths are the most exercised. Preprocessed languages are supported through custom syntaxes rather than first-class parsing, which means a SCSS or Less user depends on a separate package for that half of the work.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository received new commits within the last day.
What is it written in?
Mainly JavaScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 7, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The rule set, and the four jobs it is meant to do

The README's own description is short: a mighty CSS linter that helps you avoid errors and enforce conventions. Everything else follows from that pair of verbs. Avoiding errors splits three ways in the project's framing. There are invalid things, such as malformed grid areas. There are valid things that are nonetheless problematic, such as duplicate selectors. And there are unknown things, such as misspelled property names, where a typo produces no parse error at all.

Enforcing conventions splits four ways. You can disallow things, such as specific units. You can enforce naming patterns, for custom properties or anything else. You can set limits, such as a maximum number of ID selectors. And you can specify notations, for example for modern color functions.

That list is the clearest statement of what the tool is for, and it is worth noticing that two of the four enforcement categories, naming patterns and notation specification, have no equivalent in most linters. A JavaScript linter checks whether code parses and whether names follow a convention. A CSS linter has to check whether a declaration is legal, whether a selector can match anything at all, and whether the value is written the way your team decided.

The count is over 100 built-in rules. That number is also a cost: every rule is a promise about a language that is still gaining features, and the release history below shows what maintaining that promise costs.

Autofix, plugins, shareable configs and how they compose

Four extension mechanisms are listed in the features section, and they sit at different levels.

Autofix is the one that changes the most about day to day. The README claims stylelint automatically fixes problems where possible, which is true for a large class of stylistic rules and false for the majority of correctness rules. A duplicate selector, an unknown property name, and a color notation problem are all in different categories: one can be deleted, one can be renamed if you can guess the intent, and one can be rewritten safely. Any project deciding how much automation to trust should start by fixing a subset of rules and reading the diff.

Plugins are how you add rules of your own, and the developer guide has a dedicated page on writing them. Shareable configs are how you distribute a rule set, and they can be extended by others, which is how the ecosystem fragments into `stylelint-config-standard` and its variants. Customization covers the middle ground, where you set rule options in your own config rather than adopting someone else's package.

The package layout shows how the pieces are shipped. `package.json` exposes the library entry at `lib/index.mjs` with types alongside it, exposes internals under `./lib/utils/*` for plugins that need them, and declares a single binary at `bin/stylelint.mjs`. The published `files` array excludes tests and rule READMEs, which tells you the docs for individual rules travel separately from the code.

One more item in the README deserves a flag rather than a quotation. It names 15k unit tests and names Google and GitHub as users. Test counts and adopter names are the kind of evidence that dates quickly and tells you little about whether a specific rule will behave the way you need, so treat them as context rather than as an argument.

Getting past CSS with custom syntaxes

The README states two extension points for languages that are not CSS. Stylelint can extract embedded styles from HTML, from Markdown, and from CSS-in-JS template literals. And it can parse CSS-like languages such as SCSS, Sass, Less, and SugarSS.

Both are worth reading carefully, because the wording hides an important distinction. Custom syntaxes are a PostCSS concept, and Stylelint sits on PostCSS. The `topics` list says so. What a custom syntax actually does is hand Stylelint a different parser, so that constructs your preprocessor understands are tokenized rather than rejected. Once that parsing succeeds, the rules that operate on the token stream still run.

The practical consequence is that SCSS variables, nesting, and mixins will not trip a syntax error, but neither are they the subject of any built-in rule. Nothing in the README suggests rules for preprocessor semantics. There are separate community packages for that, named in the search terms for this project as `stylelint-scss` and related configs.

The same applies to CSS-in-JS template literals. Extracting styles from them means Stylelint can lint the CSS you wrote inside a styled-components or similar template. It does not mean Stylelint understands the JavaScript around it, which is ESLint's job.

The `keywords` array in `package.json` lists css, scss, sass, less, sugarss, css-in-js and markdown, so the intent is broad. The developer guide has a page on writing custom syntaxes if you need one the ecosystem does not already provide.

The release notes are mostly about being wrong

Three recent releases tell you more about the state of the tool than the feature list does.

Version 17.15.0, published 2026-09-04, added one rule and two rule options and fixed four bugs. The new rule is `selector-no-unmatchable`, which flags selectors that cannot match anything, a check that needs real knowledge of `:has()`, pseudo-elements and combinators. Also added was an `ignoreFunctions: []` option on `color-named` and `color-no-hex`. The four fixes are all about being wrong in specific ways: false positives from `custom-property-no-missing-var-function` when anchor positioning is used, an autofix in `declaration-block-no-redundant-longhand-properties` for the `font` shorthand, false positives in `declaration-property-max-values` for interpolated inline expressions, and false negatives in `selector-no-invalid` for pseudo-elements, combinators and nested `:has()`.

Version 17.14.1 fixed the `quiet` option so it actually suppresses warning reports, a reported range problem for unknown rules, an autofix that produced invalid `background` shorthand when `background-size` was present, and `rule-empty-line-before` false positives for shared-line comments. Version 17.14.0 is mostly performance: module path resolution, dynamically importing timing data only when needed, and a false negative in `function-calc-no-unspaced-operator` for unspaced operators after a multiplication or division.

Read together, this is a project doing maintenance work rather than adding surface area. That is the right sign for a linter, because a linter's failure mode is crying wolf and getting disabled. It also means upgrades are worth taking, and that pinning to an old minor version buys you less than you might expect.

Prettier, ESLint, and the line stylelint draws

The README takes a clear position on the formatter question, recommending that you use a pretty printer like Prettier alongside Stylelint because linters and pretty printers are complementary. That is the correct division and it is worth being precise about it. Prettier reformats. It decides where the whitespace and line breaks go, and it is safe to run on a whole file because its output is a function of the input.

Stylelint decides whether something should be there at all. A rule can say a color must be written in a particular notation, that a selector must not exceed a length, that a property is unknown. Many of those rules are not expressible as a formatting transformation, and the ones that involve renaming or removing cannot be inferred from the file alone.

Against ESLint the boundary is the file type. ESLint checks JavaScript and TypeScript, and the Stylelint ecosystem has an `eslint-config-stylelint` for keeping rule configuration consistent across the two, plus `eslint-plugin-...` packages where stylelint results are surfaced inside ESLint. The repository lints itself in all three directions at once, which is a decent illustration of how the tools coexist:

json
"lint:formatting": "prettier . --check --cache",
"lint:js": "eslint . --cache --max-warnings=0",
"lint:md": "remark . --quiet --frail",
"lint:types": "tsc"

Four separate commands behind one `lint` script, one per tool, and the JavaScript one set to fail on any warning. Stylelint itself would sit in a fifth slot as its own script.

The docs tree tells you where the answers are

The README is almost entirely a table of contents, which is a deliberate choice and a reasonable one for a tool with this much surface. The guides section maps out where each kind of question lives.

The user guide covers getting started, customizing, configuring, rules, ignoring code, the CLI, the Node.js API, the PostCSS plugin, options, and the handling of errors and warnings. Two entries in that list decide which integration you need. The CLI page is for a standalone command, the Node.js API is for calling it from a script or build tool, and the PostCSS plugin is for embedding it in a PostCSS pipeline where another tool is already driving.

The developer guide covers writing plugins, writing custom syntaxes, and writing custom formatters. That last one matters if you are integrating stylelint into a tool that needs output in a specific shape rather than the default.

The migration guides are the most practically important section and the README lists four of them: migrating to 17.0.0, 16.0.0, 15.0.0, and 14.0.0. Major versions here remove deprecated behavior rather than adding it, so an upgrade path exists for anyone several majors behind. The `docs/about/semantic-versioning.md` page sets out the policy that explains why. There are also maintainer guides for issues, pull requests and releases, and the repository carries a `.changeset/` directory, which is the tool those releases are generated from.

So the honest summary of the README is that it will not tell you how to configure anything. It tells you what the categories are, points at the page for each one, and hands you the changelog.

Editorial conclusion

stylelint is at its best on plain CSS, where the built-in rule set is deep and the autofix paths are the most exercised. Preprocessed languages are supported through custom syntaxes rather than first-class parsing, which means a SCSS or Less user depends on a separate package for that half of the work. The honest measure of the project is in its release notes rather than its feature list: releases 17.14.0 through 17.15.0 are almost entirely false positive and false negative fixes, which is what maintaining a rule set against the CSS spec looks like in practice. Install it from npm, adopt one of the shareable configs instead of writing rules from scratch, run it alongside Prettier rather than instead of it, and read the migration guide for your target major version before upgrading.

Frequently asked questions

What are the key differences between Prettier and Stylelint?

Prettier reformats a file: it decides whitespace, line breaks, and quoting, and its output is a pure function of the input. Stylelint decides whether something should be there, using over 100 rules covering invalid syntax, unmatched selectors, misspelled properties, and convention rules for units, naming, and notation. The Stylelint README recommends running them together rather than choosing between them.

How to install stylelint?

It is published to npm as `stylelint`, which is what the README's npm version badge tracks and what `package.json` declares as the package name. The README itself does not include an install command, because installation depends on which of its several interfaces you want: the CLI binary at `bin/stylelint.mjs`, the Node.js API entry at `lib/index.mjs`, or the PostCSS plugin.

Can stylelint check SCSS and Less files?

Yes, through custom syntaxes built on PostCSS, which the README lists alongside SCSS, Sass, Less and SugarSS, plus a separate mechanism for extracting embedded styles from HTML, Markdown and CSS-in-JS template literals. The parsing is handled by the syntax; the built-in rules operate on the resulting token stream and do not check preprocessor semantics, which is what packages like stylelint-scss cover.

Should I trust stylelint autofix on an existing codebase?

Apply it rule by rule and read the diff, rather than running it across everything at once. The 17.14.1 release fixed an autofix in `declaration-block-no-redundant-longhand-properties` that was producing invalid `background` shorthand when `background-size` was present, and 17.15.0 fixed its handling of the `font` shorthand, so the fix paths do get bugs too. Start with a stylistic rule you agree with and expand from there.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. stylelint/stylelint on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/stylelint-stylelint.svg)](https://hysenlabs.com/projects/stylelint-stylelint)