Gale
An extremely fast CSS linter. Drop-in replacement for Stylelint.
Gale reads your existing .stylelintrc, runs the same rules, and produces the same output. Just 10x-100x faster.
One line change in your package.json. No config migration.
Benchmarks
Real-world benchmarks using hyperfine (10 runs, 3 warmup) on an Apple M4 Max. Each repo uses its own Stylelint config. Results vary by machine -- run ./benchmarks/benchmark.sh to reproduce on yours.
| Repository | Files | Stylelint | Gale | Speedup |
|---|---|---|---|---|
| Angular Components | 621 | 0.743s | 0.008s | 96x |
| Fundamental Styles | 392 | 3.628s | 0.060s | 61x |
| GOV.UK Frontend | 149 | 2.352s | 0.044s | 54x |
| Discourse | 356 | 0.529s | 0.010s | 51x |
| Joomla | 169 | 1.033s | 0.025s | 41x |
| Carbon | 1,116 | 0.385s | 0.010s | 38x |
| Bootstrap | 99 | 0.737s | 0.021s | 35x |
| Gutenberg | 778 | 0.447s | 0.013s | 34x |
| PatternFly | 204 | 0.377s | 0.013s | 29x |
| SLDS | 446 | 0.323s | 0.014s | 24x |
Parity: 0 false positives and 0 false negatives across all 22 tested repositories (5,790 files).
Quick start
# Install
# Lint (uses your existing .stylelintrc)
# Autofix
Migrate from Stylelint
Change one line in package.json:
{
"scripts": {
- "lint:css": "stylelint 'src/**/*.css'"
+ "lint:css": "gale 'src/**/*.css'"
}
}
Your .stylelintrc stays exactly the same. Gale reads the same config files, follows the same extends chains, honors /* stylelint-disable */ comments, and produces the same JSON output format.
Installation
npm (recommended)
The npm package automatically downloads the correct platform binary on install. Supported platforms: macOS (arm64, x64), Linux (x64, arm64).
Cargo
The crate is named gale-lint on crates.io (since gale was taken), but the installed binary is called gale.
From source
# Binary at target/release/gale
GitHub releases
Download pre-built binaries from GitHub Releases.
What's supported
260+ built-in rules
Gale ships 260+ built-in rules across four categories:
| Category | Count | Examples |
|---|---|---|
| Core Stylelint | 144 | block-no-empty, color-no-invalid-hex, property-no-unknown |
SCSS (scss/*) |
44 | scss/at-rule-no-unknown, scss/no-duplicate-mixins, scss/dollar-variable-pattern |
Stylistic (@stylistic/*) |
59 | stylistic/indentation, stylistic/declaration-colon-space-after, stylistic/no-eol-whitespace |
Order (order/*) |
3 | order/order, order/properties-order, order/properties-alphabetical-order |
SCSS and stylistic rules are built in -- no extra plugins required.
Config compatibility
All Stylelint config formats are supported:
| File | Format |
|---|---|
gale.json |
JSON (native) |
gale.toml |
TOML (native) |
.stylelintrc |
JSON or YAML |
.stylelintrc.json |
JSON |
.stylelintrc.yml / .yaml |
YAML |
stylelint.config.js / .cjs |
JavaScript |
Feature overview
- SCSS and Less out of the box (no plugins needed)
- Autofix via
--fix - File caching via
--cache(skips unchanged files) - LSP server for editor integration (
--lsp) - Parallel linting using all CPU cores
- Inline disable comments (
stylelint-disableandgale-disable) - JSON, text, and compact output formatters matching Stylelint's format
extendswith built-in presets, npm packages, and relative paths.galeignorefiles (gitignore syntax) for custom exclusions
Not yet supported
- Custom JavaScript plugins. Third-party rule packages (community plugins) are not supported. Gale only runs its built-in rules.
package.jsonconfig. The"stylelint"field inpackage.jsonis not read.- Sass indented syntax.
.sassfiles are not supported (.scssworks fine).
Configuration
Gale searches for config files walking up from the working directory. To generate a starter config:
Example config
Rule value formats
| Format | Meaning |
|---|---|
true |
Enable at error severity |
false or "off" |
Disable |
"error" |
Enable at error severity |
"warning" |
Enable at warning severity |
["error", { options }] |
Enable with options |
Built-in presets
| Preset | Description |
|---|---|
gale:recommended |
Sensible defaults (29 rules: 15 error + 14 warning) |
gale:all |
All rules enabled at warning severity |
You can also extend npm packages like stylelint-config-standard directly.
Extends resolution
The extends field supports:
| Value | Resolution |
|---|---|
"gale:recommended" |
Built-in preset |
"gale:all" |
Built-in preset |
"./path/to/config.json" |
Relative path to another config file |
"stylelint-config-standard" |
npm package (resolved from node_modules/) |
Resolution is recursive with cycle detection. Later extends entries override earlier ones. User rules always override extended rules.
CLI reference
gale [OPTIONS] [FILES]...
| Flag | Description |
|---|---|
<files> |
Files, directories, or glob patterns to lint |
--fix |
Automatically fix problems |
-q, --quiet |
Only report errors |
-f, --formatter <type> |
Output: text (default), json, compact |
-c, --config <path> |
Config file path |
--max-warnings <n> |
Error if warnings exceed threshold |
--cache |
Skip unchanged files |
--cache-location <path> |
Custom cache file path (default: .gale_cache) |
--stdin |
Read from stdin |
--stdin-filename <name> |
Virtual filename for stdin (default: stdin.css) |
--ignore-path <file> |
Custom ignore file (gitignore syntax) |
--no-ignore |
Disable all ignore file processing |
--print-config <file> |
Print resolved config as JSON |
--init |
Generate starter config |
--lsp |
Start LSP server |
Editor integration
Any LSP-compatible editor
Works with Neovim, Helix, Zed, and any editor supporting the Language Server Protocol.
Development
Prerequisites
- Rust 2024 edition (1.85+)
- Python 3 (for differential tests)
- Node.js 16+ (for differential tests and npm packaging)
Build and test
Run the linter
Debug and profiling
GALE_DEBUG_PERF=1 GALE_LOG=debug
Differential testing
Compare Gale output against Stylelint on real-world repositories:
The test corpus includes Bootstrap, Gutenberg, Carbon, Angular Components, wp-calypso, Discourse, GOV.UK Frontend, Spectrum CSS, Docusaurus, Grafana, Material UI, freeCodeCamp, PatternFly, Primer CSS, Elastic EUI, Mattermost, Mastodon, JupyterLab, Joomla, SLDS, rsuite, and Fundamental Styles.
Benchmarks
Releasing
Releases are automated via GitHub Actions when you push a version tag:
# 1. Update the version in Cargo.toml (workspace.package.version)
# 2. Commit the version bump
# 3. Tag and push
&&
The release workflow will:
- Build binaries for Linux (x64, arm64) and macOS (x64, arm64)
- Create a GitHub Release with the binaries
- Publish the npm package (
@lyricalstring/gale) with the matching version
Manual npm build
# Build for current platform
# Build for all platforms (requires cross + Docker)
# Set npm package version before building
Architecture
Gale is organized as a Cargo workspace with seven crates:
gale (binary)
|
v
gale_cli CLI definition (clap), file discovery, orchestration
|
+-- gale_config Config loading, resolution, presets
+-- gale_linter Rule trait, registry, runner, 260+ built-in rules
| +-- gale_css_parser CSS/SCSS/Less parser (lightningcss + raffia)
| +-- gale_diagnostics Span, Diagnostic, LintResult, Fix/Edit types
+-- gale_formatter Output formatters (text, json, compact)
+-- gale_lsp Language Server Protocol server
| Crate | Responsibility |
|---|---|
gale_css_parser |
Wraps lightningcss (CSS) and raffia (SCSS/Less) into a unified, owned AST |
gale_diagnostics |
Core types: Span, Diagnostic, LintResult, Fix, Edit |
gale_linter |
Rule trait, RuleRegistry, LintRunner, inline disable comments, all rule implementations |
gale_config |
Config file discovery, parsing (JSON/YAML/TOML/JS), extends resolution, built-in presets |
gale_formatter |
TextFormatter, JsonFormatter, CompactFormatter matching Stylelint output |
gale_cli |
Clap CLI, file discovery with ignore support, cache layer, --fix orchestration |
gale_lsp |
LSP server for real-time editor diagnostics |
See CLAUDE.md for detailed architecture docs and how to add rules.