Stylelint: Complete Configuration Guide
Stylelint is a powerful, modern linter for CSS and CSS-like languages such as SCSS, Sass, Less, and CSS-in-JS. It helps teams enforce consistent conventions, catch errors early, and maintain a clean, readable stylesheet codebase. In this guide, we will walk through everything you need to know to configure Stylelint effectively, from installation to advanced customization.
What Is Stylelint?
Stylelint is an open-source linter written in JavaScript that analyzes your stylesheets and flags problems based on a configurable set of rules. Unlike older tools that only checked formatting, Stylelint can enforce naming conventions, detect duplicate properties, prevent vendor prefix mistakes, and even validate values against custom logic. It is plugin-driven, highly configurable, and integrates smoothly with most modern build pipelines.
Why Stylelint Matters
- Consistency: Enforces a unified style across teams, reducing review friction.
- Error prevention: Catches invalid properties, duplicate declarations, and typos before they reach production.
- Maintainability: Large stylesheets stay readable and predictable.
- Automation: Integrates with editors, CI pipelines, and pre-commit hooks.
- Ecosystem: A rich plugin ecosystem supports SCSS, Less, CSS Modules, and styled-components.
Installation
Start by installing Stylelint and a recommended configuration as development dependencies. The most common starting point is stylelint-config-standard, which bundles a sensible set of rules.
npm install --save-dev stylelint stylelint-config-standard
If you work with SCSS, also install the SCSS plugin and shared config:
npm install --save-dev stylelint-config-standard-scss stylelint-scss
Creating a Configuration File
Stylelint looks for a configuration file named .stylelintrc.json, .stylelintrc.js, .stylelintrc.mjs, or a stylelint key inside package.json. The JSON format is the most common and easiest to maintain.
{
"extends": "stylelint-config-standard",
"rules": {
"indentation": 2,
"no-duplicate-selectors": true,
"color-hex-length": "long",
"declaration-block-no-redundant-longhand-properties": true
}
}
The extends field lets you inherit rules from a shared configuration. The rules field overrides or adds specific rules on top of the extended config.
Understanding Rules
Each rule can be set to null (disabled), true (enabled with defaults), or an array where the second element is the configuration. For example:
{
"rules": {
"at-rule-no-unknown": true,
"color-no-invalid-hex": true,
"declaration-property-unit-allowed-list": {
"line-height": ["unitless", "em", "rem"]
},
"selector-class-pattern": "^[a-z][a-zA-Z0-9]+$",
"max-nesting-depth": 3
}
}
Rules are grouped into categories such as possible errors, limit language features, and stylistic issues. Possible errors are enabled by default in most shared configs because they catch real bugs.
Disabling Rules Inline
Sometimes you need to bypass a rule for a specific block. Stylelint supports inline comments for this purpose:
/* stylelint-disable-next-line color-no-hex */
.button {
background-color: #ff0000;
}
/* stylelint-disable selector-class-pattern */
.old-legacy-class {
color: red;
}
/* stylelint-enable selector-class-pattern */
Use these sparingly. Overuse defeats the purpose of linting and signals that your config may need adjustment.
Working with Plugins
Plugins extend Stylelint with custom rules. A popular example is stylelint-scss, which adds SCSS-specific checks like at-rule-no-unknown for SCSS directives.
{
"plugins": ["stylelint-scss"],
"rules": {
"at-rule-no-unknown": null,
"scss/at-rule-no-unknown": true,
"scss/dollar-variable-pattern": "^[a-z][a-zA-Z0-9]+$"
}
}
Notice that we disable the built-in at-rule-no-unknown and enable the SCSS-specific version instead. This prevents Stylelint from flagging valid SCSS directives like @include or @use.
Using Overrides
When your project mixes different stylesheet types, overrides let you apply different rules to different files. This is useful when you have both plain CSS and SCSS in the same repository.
{
"extends": "stylelint-config-standard",
"overrides": [
{
"files": ["**/*.scss"],
"extends": "stylelint-config-standard-scss",
"rules": {
"scss/at-rule-no-unknown": true
}
},
{
"files": ["**/vendor/**/*.css"],
"rules": {
"no-duplicate-selectors": null
}
}
]
}
Running Stylelint
Add a script to your package.json to run Stylelint across your project:
{
"scripts": {
"lint:css": "stylelint \"**/*.{css,scss}\"",
"lint:css:fix": "stylelint \"**/*.{css,scss}\" --fix"
}
}
The --fix flag automatically corrects problems that are safely fixable, such as formatting and ordering issues. Run the linter with:
npm run lint:css
Integrating with Editor and CI
For real-time feedback, install the Stylelint extension for VS Code or your preferred editor. Configure it to validate on save and auto-fix where possible. In your VS Code settings:
{
"stylelint.validate": ["css", "scss", "less"],
"editor.codeActionsOnSave": {
"source.fixAll.stylelint": "explicit"
}
}
For CI pipelines, add Stylelint to your workflow. Here is an example using GitHub Actions:
name: Lint CSS
on: [push, pull_request]
jobs:
stylelint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npm run lint:css
Ignoring Files
Create a .stylelintignore file to exclude vendored or generated stylesheets:
node_modules/
dist/
build/
**/vendor/**
*.min.css
Alternatively, use the ignoreFiles property inside your configuration file:
{
"ignoreFiles": ["dist/**/*", "node_modules/**/*"]
}
Customizing Severity Levels
By default, rule violations are reported as errors. You can downgrade specific rules to warnings using the severity option:
{
"rules": {
"selector-class-pattern": [true, {
"severity": "warning"
}],
"max-nesting-depth": [3, {
"severity": "warning"
}]
}
}
This is useful when migrating a legacy codebase. You can start with warnings for rules you plan to enforce later, then promote them to errors once the codebase is clean.
Best Practices
- Start with a shared config: Inherit from
stylelint-config-standardor a style guide likestylelint-config-recommendedrather than writing rules from scratch. - Enable autofix in CI cautiously: Autofix is great locally, but avoid committing autofixes silently in CI. Review changes before merging.
- Use pre-commit hooks: Tools like
lint-stagedandhuskycan run Stylelint only on changed files, keeping commits fast. - Document exceptions: When you disable a rule inline, add a comment explaining why.
- Version your config: If you share config across projects, publish it as a private package so updates propagate consistently.
- Separate style from logic: Use Stylelint for stylistic and structural rules, and rely on tools like Prettier only if your team prefers it. Avoid running both with conflicting formatting rules.
- Gradually tighten rules: Introduce new rules as warnings first, then convert to errors once the codebase complies.
Example: Pre-commit Hook with lint-staged
Install the necessary tools:
npm install --save-dev husky lint-staged
Configure lint-staged in your package.json:
{
"lint-staged": {
"*.{css,scss}": "stylelint --fix"
}
}
Set up the hook:
npx husky init
echo "npx lint-staged" > .husky/pre-commit
Now, every commit will automatically lint and fix staged stylesheet files.
Conclusion
Stylelint is an indispensable tool for any team serious about stylesheet quality. By starting with a shared configuration, layering in project-specific rules, and integrating the linter into your editor and CI pipeline, you can catch mistakes early and keep your stylesheets maintainable as they grow. The key is to begin with sensible defaults, introduce stricter rules gradually, and document any exceptions clearly. With a well-tuned Stylelint setup, your team will spend less time debating formatting and more time building great interfaces.