sass-lint and stylelint are both tools designed to analyze stylesheet code for errors, stylistic inconsistencies, and potential bugs. sass-lint was historically the go-to choice specifically for Sass and SCSS projects, offering rules tailored to Sass syntax features like mixins and nested selectors. However, it is now deprecated and no longer maintained. stylelint is the modern, community-driven standard for linting all CSS dialects, including standard CSS, Less, SCSS, and SugarSS. It features a powerful plugin architecture, auto-fixing capabilities, and active development, making it the robust choice for current and future projects.
In the world of frontend architecture, maintaining consistent styling code is just as critical as maintaining JavaScript logic. For years, developers debated between specialized linters and general-purpose ones. Today, that debate is effectively over. Let's look at why stylelint has become the undisputed standard and why sass-lint should be removed from your dependency list immediately.
The most important factor in choosing a tool is whether it will be there tomorrow.
sass-lint is officially deprecated. The maintainers have archived the repository and marked the npm package as deprecated. This means no new features, no fixes for false positives, and no support for newer Sass syntax. Relying on it is a risk to your build stability.
# npm warning you will see today
npm warn deprecated sass-lint@1.12.1: This project is deprecated. Please use stylelint instead.
stylelint is actively maintained by a large community. It releases regular updates to support new CSS specifications, fix bugs, and improve performance. It is backed by major industry players and integrates seamlessly with modern editor tooling.
# stylelint is the current standard
npm install --save-dev stylelint stylelint-config-standard
Configuring a linter should be flexible enough to match your team's specific needs without forcing a complete rewrite when requirements change.
sass-lint used a single, monolithic configuration file (.sass-lint.yml). While simple for small projects, it lacked modularity. Adding custom rules often required writing complex JavaScript files that were hard to share across teams.
# sass-lint: .sass-lint.yml (Legacy approach)
options:
formatter: stylish
rules:
indentation:
- 2
- size: 2
no-duplicate-properties:
- 2
# Adding a custom rule required complex setup
stylelint uses a modular, plugin-based configuration (usually .stylelintrc.json or stylelint.config.js). You can extend shared configs (like stylelint-config-standard) and layer your own rules on top. This makes it easy to onboard new projects and share standards across an organization.
// stylelint: .stylelintrc.json (Modern approach)
{
"extends": "stylelint-config-standard",
"rules": {
"indentation": 2,
"no-duplicate-properties": true,
"selector-class-pattern": "^[a-z][a-zA-Z0-9]*$"
},
"plugins": ["stylelint-scss"]
}
Your tooling should adapt to your stack, not force your stack to adapt to it.
sass-lint was built exclusively for Sass and SCSS. If your project introduced a plain CSS file or a Less file, sass-lint would either ignore it or crash. This created silos where different parts of your codebase had different quality gates.
// sass-lint: Only works here
.my-mixin {
@include border-radius(4px); // Specific Sass syntax
}
stylelint is universal. Out of the box, it handles standard CSS. With the official stylelint-scss plugin, it fully supports SCSS and Sass syntax, including variables, mixins, and functions. It can also lint Less, SugarSS, and even CSS-in-JS via specific processors. This allows a single linting command to cover your entire frontend codebase.
// stylelint + stylelint-scss: Works here AND in plain CSS
.my-class {
@include border-radius(4px); // Linted correctly with plugin
color: var(--main-color); // Linted correctly as standard CSS
}
Developer experience is heavily influenced by how much time you spend fixing trivial errors.
sass-lint did not support auto-fixing. If the linter found 50 indentation errors or missing semicolons, you had to fix them manually. This friction often led developers to disable rules or ignore warnings entirely.
# sass-lint: Only reports errors
$ sass-lint -v
src/styles.scss
5:3 error Indentation expected to be 2 spaces indentation
# Developer must open file and fix manually
stylelint includes a powerful --fix flag that automatically resolves many common issues, such as indentation, whitespace, and sorting. This saves hours of manual work and ensures consistent formatting without debate.
# stylelint: Report AND fix
$ stylelint "src/**/*.scss" --fix
# Automatically corrects indentation, removes duplicates, etc.
You have a large codebase using .scss files and an old .sass-lint.yml config.
sass-lint. Install stylelint, stylelint-scss, and stylelint-config-standard-scss.// package.json scripts update
{
"scripts": {
"lint:css": "stylelint \"src/**/*.scss\" --custom-syntax postcss-scss"
}
}
Your monorepo contains a React app (CSS Modules), a Vue app (SCSS), and a shared UI library (Less).
stylelint with specific overrides for each folder.sass-lint cannot handle this diversity. stylelint allows you to apply different rule sets to different file types within a single command.// stylelint.config.js in monorepo root
module.exports = {
overrides: [
{
files: "**/*.scss",
customSyntax: "postcss-scss",
rules: { /* SCSS specific rules */ }
},
{
files: "**/*.less",
customSyntax: "postcss-less",
rules: { /* Less specific rules */ }
}
]
};
You need to block merges if styling standards are violated.
stylelint in strict mode in your CI pipeline.stylelint is actively maintained, it won't break unexpectedly due to Node.js version updates, unlike the abandoned sass-lint.# .github/workflows/lint.yml
- name: Lint Styles
run: npx stylelint "src/**/*.{css,scss}" --formatter github
| Feature | sass-lint | stylelint |
|---|---|---|
| Status | 🔴 Deprecated / Archived | 🟢 Active / Standard |
| Syntax Support | Sass/SCSS only | CSS, SCSS, Less, SugarSS, CSS-in-JS |
| Auto-Fix | ❌ No | ✅ Yes (--fix) |
| Config Format | YAML (Rigid) | JSON/JS (Modular & Extensible) |
| Ecosystem | Dead | 🌱 Massive (Plugins, Shared Configs) |
| Recommendation | ❌ Remove Immediately | ✅ Use for All Projects |
There is no longer a technical trade-off to consider here. sass-lint served a purpose in the past when tooling for Sass was fragmented, but that time has passed.
sass-lint is a legacy tool that introduces risk. It should be treated as technical debt. If you see it in a package.json, plan a migration sprint to remove it.
stylelint is the professional choice. It offers the flexibility to handle any stylesheet language, the power to auto-fix errors, and the security of an active community. For any architect making decisions today, stylelint is the only logical path forward for ensuring code quality and consistency in your stylesheets.
Do NOT choose sass-lint for any new project or active codebase. This package has been officially deprecated and archived by its maintainers, meaning it receives no security updates, bug fixes, or support for modern Sass features. Using it introduces technical debt and risks breaking your build pipeline as dependencies age. If you are currently using it, you should plan an immediate migration to stylelint.
Choose stylelint for virtually every scenario, whether you are writing plain CSS, SCSS, Less, or using CSS-in-JS. It is the only actively maintained option with a vast ecosystem of shared configurations and plugins. Select stylelint if you need reliable auto-fixing, integration with modern build tools (like Vite or Webpack), and the ability to enforce consistent styling rules across a large team. Its flexibility allows you to start with a preset and gradually add custom rules as your project grows.
A Node-only Sass linter for both sass and scss syntax!
You can get sass-lint from NPM:
Install globally
npm install -g sass-lint
To save to a project as a dev dependency
npm install sass-lint --save-dev
Sass-lint can be configured from a .sass-lint.yml or .sasslintrc file in your project. The .sasslintrc file can be in either JSON format or YAML. Both formats are interchangeable easily using tools such as json2yaml. If you don't either file in the root of your project or you would like all your projects to follow a standard config file then you can specify the path to one in your project's package.json file with the sasslintConfig option.
For example:
{
"name": "my-project",
"version": "1.0.0",
"sasslintConfig": "PATH/TO/YOUR/CONFIG/FILE"
}
Use the Sample Config (YAML) or Sample Config (JSON) as a guide to create your own config file. The default configuration can be found here.
Migrating from SCSS-Lint: If you already have a config for SCSS-Lint, you can instantly convert it to the equivalent Sass Lint config at sasstools.github.io/make-sass-lint-config.
The following are options that you can use to config the Sass Linter.
The files option contains two properties, include and ignore. Both can be set to either a glob or an array of glob strings/file paths depending on your projects' needs and setup.
For example below we are providing a singular glob string to our include property and an array of patterns to our ignore property:
files:
include: 'sass/**/*.s+(a|c)ss'
ignore:
- 'sass/vendor/**/*.scss'
- 'sass/tests/**/*.scss'
As mentioned you can also provide an array to the include property like so
files:
include:
- 'sass/blocks/*.s+(a|c)ss'
- 'sass/elements/*.s+(a|c)ss'
ignore:
- 'sass/vendor/**/*.scss'
- 'sass/tests/**/*.scss'
For all rules, setting their severity to 0 turns it off, setting to 1 sets it as a warning (something that should not be committed in), and setting to 2 sets it to an error (something that should not be written). If a rule is set to just a severity, it will use the default configuration (where available).
If you want to configure options, set the rule to an array, where the first item in the array is the severity, and the second item in the array is an object including the options you would like to set.
Here is an example configuration of a rule, where we are specifying that breaking the indentation rule should be treated as an error (its severity set to two), and setting the size option of the rule to 2 spaces:
rules:
indentation:
- 2
-
size: 2
Special comments can be used to disable and enable certain rules throughout your source files in a variety of scenarios. These can be useful when dealing with legacy code or with certain necessary code smells. You can read the documentation for this feature here.
Below are examples of how to use this feature:
// sass-lint:disable border-zero
p {
border: none; // No lint reported
}
// sass-lint:disable border-zero, quotes
p {
border: none; // No lint reported
content: "hello"; // No lint reported
}
p {
border: none; // sass-lint:disable-line border-zero
}
p {
// sass-lint:disable-block border-zero
border: none; // No result reported
}
a {
border: none; // Failing result reported
}
// sass-lint:disable border-zero
p {
border: none; // No result reported
}
// sass-lint:enable border-zero
a {
border: none; // Failing result reported
}
// sass-lint:disable-all
p {
border: none; // No result reported
}
// sass-lint:enable-all
a {
border: none; // Failing result reported
}
Sass Lint v1.1.0 introduced the ability to run Sass Lint through a command line interface. See the CLI Docs for full documentation on how to use the CLI.
There are small differences which are useful to understand over other CLI tools you may have encountered with other linters.
By default any rule set to severity: 2 in your config will throw an error which will stop the CLI on the first error it encounters. If you wish to see a list of errors and not have the CLI exit then you'll need to use the -q or --no-exit flag.
Warnings or any rule set to severity: 1 in your config by default will not be reported by the CLI tool unless you use verbose flag -v or --verbose.
With this in mind if you would like to have the CLI show both warnings and errors then at the very least your starting point to use the cli should be the following command.
sass-lint -v -q
Below is an example of the command being used to load a config -c app/config/.sass-lint.yml file, show errors and warnings on the command line, and target a glob pattern **/*.scss:
sass-lint -c app/config/.sass-lint.yml '**/*.scss' -v -q
or with long form flags
sass-lint --config app/config/.sass-lint.yml '**/*.scss' --verbose --no-exit
By default when specifying a directory/file to lint from the CLI you would do something similar to the following
sass-lint 'myapp/**/*.scss' -v -q
or with long form flags
sass-lint 'myapp/**/*.scss' --verbose --no-exit
Notice that you need to wrap glob patterns in quotation marks
If you want to specify multiple input sources then you need to include a single comma and a space , to separate each pattern as shown in the following
sass-lint 'myapp/dir1/**.*.scss, myapp/dir2/**/*.scss' -v -q
or with long form flags
sass-lint 'myapp/dir1/**.*.scss, myapp/dir2/**/*.scss' --verbose --no-exit
If you don't include the extra space after the comma then the multiple patterns will not be interpreted correctly and you could see sass-lint fail.
To add a list of files to ignore tests/**/*.scss, dist/other.scss into the mix you could do the following:
sass-lint -c app/config/.sass-lint.yml '**/*.scss' -v -q -i 'tests/**/*.scss, dist/other.scss'
or with long form flags
sass-lint --config app/config/.sass-lint.yml '**/*.scss' --verbose --no-exit --ignore 'tests/**/*.scss, dist/other.scss'
Notice that glob patterns need to be wrapped in quotation or single quote marks in order to be passed to sass-lint correctly and if you want to ignore multiple paths you also need to wrap it in quotation marks and separate each pattern/file with a comma and a space
,.
This will be revisited and updated in sass-lint v2.0.0.
For further information you can visit our CLI documentation linked below.
Certain static site generators such as Jekyll include the YAML front matter block at the top of their scss file. Sass-lint by default checks a file for this block and attempts to parse your Sass without this front matter. You can see an example of a front matter block below.
---
# Only the main Sass file needs front matter (the dashes are enough)
---
.test {
color: red;
}
We welcome all contributions to this project but please do read our contribution guidelines first, especially before opening a pull request. It would also be good to read our code of conduct.
Please don't feel hurt or embarrassed if you find your issues/PR's that don't follow these guidelines closed as it can be a very time consuming process managing the quantity of issues and PR's we receive. If you have any questions just ask!
Our AST is Gonzales-PE. Each rule will be passed the full AST which they can traverse as they please. There are many different node types that may be traversed, and an extensive API for working with nodes. The file of the rule must have the same name as the name of the rule. All of the available rules are in our rules directory. Default options will be merged in with user config.