Getting started
Purge unused CSS with the Monsoon CLI
The full stylesheet is fine for most sites. When you want to ship less, monsooncss purge scans your files and writes a stylesheet that keeps only the utilities they use. It runs once before you deploy and never changes your source files.
When to purge
Purging is optional. The full file is one cached request of about 88 kB with brotli, and it gives you every class while you work. Purge when first visit weight matters most (a landing page, a small marketing site), when a performance budget asks for less unused CSS, or when you self host the CSS anyway and already have a deploy step.
These are real numbers from this release. The kitchen sink demo in the repository uses a wide mix of utilities; the single card page is the first page from the introduction:
| File | Utility rules | Raw | gzip | brotli |
|---|---|---|---|---|
Full monsoon.min.css | all | 1320.5 kB | 145.4 kB | 88.3 kB |
| Purged, kitchen sink demo | 294 of 16,351 | 281.2 kB | 48.4 kB | 39.2 kB |
| Purged, single card page | 22 of 16,351 | 266.1 kB | 45.8 kB | 37.1 kB |
The purged files are close in size because purging removes utilities only. The theme, the reset and the component layer are always kept, as explained below. Keep the full file during development so any class you try just works, and purge for production.
Run it
Pass one or more files, folders or glob patterns, and an output file. Running it against the kitchen sink demo in the Monsoon repository prints:
npx monsooncss purge demo/kitchen-sink.html -o public/monsoon.cssmonsooncss purge: scanned 1 file
kept 294 of 16351 utility rules
public/monsoon.css: 281.2 kB raw, 48.4 kB gzip, 39.2 kB brotli (full build 88.3 kB brotli)The report goes to standard error. Without -o, the CSS itself goes to standard output, so redirecting works and the report never ends up inside the file:
npx monsooncss purge "src/**/*.html" > public/monsoon.cssOptions
| Option | What it does |
|---|---|
<glob...> | Files, folders or glob patterns to scan. At least one is required. |
-o, --out <file> | Write the CSS to this file and print a size report. Missing folders are created. |
--safelist <a,b,c> | Comma separated classes to keep even if no scanned file mentions them. |
--no-minify | Write readable, indented CSS instead of minified CSS. |
--css <file> | Purge a different copy of the stylesheet instead of the bundled dist/monsoon.css. It must be the readable file: the minified one has no marker where the utilities start. |
-h, --help | Print usage and examples. |
-v, --version | Print the installed version. |
# readable output, to inspect what was kept
npx monsooncss purge "src/**/*.html" --no-minify -o build/monsoon.css
# keep classes that only exist at runtime
npx monsooncss purge "src/**/*.html" --safelist bg-success,bg-danger -o public/monsoon.cssFiles, folders and globs
*matches inside one folder,**matches any depth,?matches one character,[abc]matches a set, and{html,php}expands to alternatives.- A path without wildcards can be a file or a folder. A folder is scanned completely.
node_modules,.git,.hgand.svnfolders are always skipped.- Quote your patterns. The tool expands them itself, so they behave the same in every shell, Windows included.
Scan every file that can contain a class name: templates, components, and scripts that build markup. Some typical commands:
# a JavaScript app
npx monsooncss purge "src/**/*.{html,js,jsx,tsx,vue,svelte,astro}" -o public/monsoon.css
# Laravel
npx monsooncss purge "resources/views/**/*.blade.php" "resources/js/**/*.{js,vue}" -o public/css/monsoon.css
# Django and Rails in one go
npx monsooncss purge "templates/**/*.html" "app/views/**/*.erb" -o static/monsoon.cssHow scanning works
The scanner does not parse HTML or JavaScript. It reads each file as text and splits it on whitespace, quotes, backticks, the backslash and the characters < > = { } ( ) ; , | & !. Every piece is a candidate class name, and a copy with a trailing . or : removed is added too. A utility rule is kept when a class in its selector is one of the candidates.
The consequence is simple: every class must appear in your source as a complete string. Names assembled from pieces at runtime are invisible to the scanner:
// Found: both full class names appear in the file
const tone = failed
? 'bg-danger text-danger-foreground'
: 'bg-success text-success-foreground';
// Not found: the file only contains "bg-" and the variable name
const badge = 'bg-' + status;When names come from data, such as a status stored in a database, either map each value to a full class name in your code, or list the classes with --safelist.
Variant classes are matched as written. If your markup uses md:flex, the rule for md:flex is kept, and the plain flex rule is kept only if flex also appears on its own.
Extra candidates are harmless. Ordinary words in your text that happen to be class names, such as block or hidden, only keep a few more small rules.
What is always kept
Purging removes unused utility rules and nothing else. Everything that comes before the utilities in the stylesheet stays:
- the reset in the
basecascade layer, - the theme:
--seed, every derived token, light and dark mode, and the static fallback for browsers without relative colors, - the palette custom properties,
--color-slate-50to--color-rose-950, - the keyframes used by the animation utilities,
- the whole component layer, so
btn,cardand every other component class keep working without a safelist.
That is why a purged file has a floor of about 37 kB with brotli, even for a page that uses a handful of utilities. Your custom properties such as var(--primary) also keep working in a purged file, because the tokens are never removed.
The classes command
monsooncss classes lists every utility class in the stylesheet, variants included, one per line. --filter keeps the names that contain a piece of text, and --json prints a JSON array:
npx monsooncss classes --filter grid-colsgrid-cols-1
grid-cols-2
grid-cols-3
...
sm:grid-cols-1
sm:grid-cols-2
...# check whether a variant exists before you write it
npx monsooncss classes --filter md:grid
# every class as JSON, for editor tooling or your own checks
npx monsooncss classes --json > monsoon-classes.jsonThe filter is a plain substring match, so --filter md:grid also shows the container variant @md:grid. The command reads the same stylesheet as purge, and --css works here too.
npm scripts and CI
Install the package as a dev dependency so everyone runs the same version, then add a script. npm runs a script named prebuild automatically before build:
{
"scripts": {
"build:css": "monsooncss purge \"src/**/*.{html,js}\" -o dist/monsoon.css",
"prebuild": "npm run build:css",
"build": "your-build-command"
},
"devDependencies": {
"monsooncss": "^0.2.0"
}
}In CI, install the dependencies and run the same script before you deploy. The command exits with code 1 when none of the patterns match a file, when an option is unknown or when the stylesheet cannot be found, so a broken path fails the job instead of shipping an empty stylesheet:
npm ci
npm run build:cssTreat the purged file as a build artifact: generate it in CI on every deploy rather than committing it, so it can never fall behind your templates.
Frequently asked questions
Do I need to purge?
No. The full file is about 88 kB with brotli and is cached after the first visit. Purging is an optional production step.
Why did a class disappear after purging?
Its full name does not appear in any scanned file. Check that the file is matched by your patterns and that the class is not built from pieces at runtime, or add it with --safelist.
Does purging remove component classes?
No. The component layer, the reset and the theme are always kept. Only utility rules are removed.
Can I purge the minified file?
Purge reads the readable dist/monsoon.css and minifies its output by default. Pass --no-minify for readable output.