CLI tool
csstools/postcss-plugins avatar
csstools/postcss-plugins

PostCSS Plugins: one monorepo turning CSS specs into build-time transforms

PostCSS Tools and Plugins

1,059 stars83 forksCSSMIT-0

At a glance

What is it?
The csstools/postcss-plugins repository is a monorepo of PostCSS plugins, plugin packs, tokenizers, parsers, Stylelint plugins, and CLI tools that convert newer CSS syntax into output older browsers understand. The centrepiece is postcss-preset-env, and the driving mechanism is the CSSDB feature database.
Who is it for?
Adopt postcss-preset-env when you support browsers that lack a CSS feature and want the transform maintained by the people who track the spec, rather than hand-writing fallbacks that go stale. Do not adopt the individual plugins piecemeal unless you know exactly which transforms you need, since the pack exists precisely to coordinate them.
Can I use it commercially?
Yes. MIT-0 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 last received commits 2 days ago.
What is it written in?
Mainly CSS, according to GitHub's language statistics.

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

Editorial analysis

A monorepo where the unit of release is a workspace, not a repository

The csstools/postcss-plugins repository is not a single plugin. It is a workspace root, and the root package.json is marked private with an empty description, which is what a monorepo root looks like when it is not itself published. The workspaces list names the members: a `packages/` group for css tokenizers, parsers, and common utilities, then `plugins/`, `plugin-packs/`, `cli/`, `experimental/`, and `plugins-stylelint/`.

Several packages are listed explicitly, which usually means they are exceptions to a wildcard. There is `packages/color-helpers`, `packages/css-tokenizer`, `packages/css-parser-algorithms`, `packages/css-calc`, `packages/css-color-parser`, `packages/cascade-layer-name-parser`, and `packages/media-query-list-parser`. Underneath those, the `packages/*` wildcard covers the rest. The plugin and pack directories follow the same pattern, with `plugins/postcss-progressive-custom-properties` and `plugins/postcss-debug-logger` named before the `plugins/*` catch-all.

This structure matters for a practical reason. A plugin like the one that transforms cascade layers needs to parse layer names, and the parser for that lives in `packages/cascade-layer-name-parser` rather than inside the plugin. So a consumer who installs one plugin may pull in several packages, and a consumer who installs the whole preset pulls in dozens. The dependency graph is the design, and it is why the repository also carries `rollup/` for building and `api-extractor.json` for API surface reporting across all of it.

The root scripts show the same shape. `build`, `docs`, `lint`, and `test` all fan out with `--workspaces --if-present`, so a package without a docs script simply skips it. The `everything` script chains lint, knip, build, docs, and test, and `knip` is there to detect unused files and dependencies across the workspace.

CSSDB is the catalogue and the plugins are its implementation

The stated focus of the project is standard CSS transforms, and the mechanism is described in two steps. First they keep track of new features through CSSDB, with a link to the CSSDB site and to the separate CSSDB repository. Then they do their best to create a PostCSS plugin that can convert that new syntax, function, or rule so every browser can understand it.

That is a meaningfully different model from the usual one. Instead of a plugin author deciding what to support, there is a database of features and an implementation per feature. The plugin is downstream of the catalogue, and the catalogue is downstream of the spec.

The project is careful about the limits of that approach. The sentence about converting new syntax is followed by an explicit acknowledgement that it is not always possible, and then a count: while it is not always possible, these plugins enable over 50 features.

The second stated focus is developer experience, and it is a different kind of work. From time to time they publish plugins that are not related to a standard CSS spec but that they think will help developers. The `plugins/postcss-debug-logger` package in the workspace list is the clearest example of that category, and `plugins/postcss-progressive-custom-properties` is a plugin whose subject is a transform rather than a spec feature.

So the repository produces two kinds of artefact, and it is worth keeping them apart in your head. Spec plugins answer what should a browser receive. The others answer what should a developer receive while writing the CSS in the first place.

preset-env is the front door, and it wants autoprefixer gone

The quick start is short, and it starts with a single instruction: install `postcss-preset-env` from npm and add it to your configuration. The configuration snippet is a plain PostCSS plugin list:

js
const postcssPresetEnv = require('postcss-preset-env');

const yourConfig = {
	plugins: [
		/* other plugins */
		/* remove autoprefixer if you had it here, it's part of postcss-preset-env */
		postcssPresetEnv({
			/* pluginOptions */
			features: {},
		})
	]
}

Two things in that snippet matter more than they look. The first is the comment sitting inside the plugin list: remove autoprefixer if you had it there, because it is part of postcss-preset-env. Leaving autoprefixer in place means the same work runs twice, which at best wastes build time and at worst produces conflicting output where two tools make different assumptions about the same declaration.

The second is the `features` option. It appears with an empty object and the comment marking it as plugin options, which is the sign that this is the knob. Each feature in CSSDB has a stage, and the preset uses the stage information to decide what to transform. An empty `features` object means the default set, and the way to narrow or widen that set is through this option rather than by dropping plugins, which is the difference between a coordinated transform set and a pile of individual ones.

The preset is a plugin pack, and the repository lists the packs under `plugin-packs/`, with the pack's own documentation in its directory. It is also the subject of a dedicated site, since the homepage recorded for the project is the preset-env site at preset-env.cssdb.org.

The repository ships more than PostCSS plugins

The overview section lists more categories than plugins, and each points at a directory in the tree.

There are packages, described as css tokenizers and parsers, and common utilities. There are the PostCSS plugins themselves. There is PostCSS Preset Env as its own plugin pack. There are Stylelint plugins under `plugins-stylelint/`, which is a different audience and a different lifecycle from the build-time transforms. There are CLI tools under `cli/`, and sites under `sites/`.

There is also a directory called `postcss-recipes/`, listed as PostCSS recipes, and it is the least explained item on the list. The name suggests worked configurations rather than published packages, and given that the tree also contains `e2e/` and `e2e-package-managers/` directories, the recipes are likely tested end to end. The `e2e-package-managers/` name in particular suggests the repository checks that its packages install correctly under more than one package manager, which is a common source of breakage in a project that publishes dozens of small packages.

Two other root files tell you how the project operates. `UPDATING_POSTCSS.md` is a guide for updating PostCSS, which for a plugin ecosystem means handling the API changes between major versions of the host tool. `AUTHORING_GUIDELINES.md` covers how to write a plugin in this repository, which matters if you plan to contribute one rather than only use them. `SECURITY.md` and `CODE_OF_CONDUCT.md` are present as well, and the licence is MIT-0, recorded both in the root package.json and in a `LICENSE.md` file.

The MIT-0 licence is worth a note. It is the MIT licence without the requirement to keep the copyright notice, which is a common choice for small tooling packages.

Tokenizers and parsers are the layer everything else builds on

The packages directory is the most interesting engineering decision in the repository, and it is the one that is least likely to be obvious from the name.

There is a `css-tokenizer` and a `css-parser-algorithms` package, which is the standard split: tokenizing turns a string into a stream of tokens, and the parser algorithms turn that stream into a structured syntax tree. There is a `css-color-parser` and a `color-helpers` package, and a `css-calc` package, which is what you would expect for a repository that transforms colour and calculation syntax.

The two specialised parsers are the most telling. A `cascade-layer-name-parser` and a `media-query-list-parser` are not general CSS tools. They exist because a specific transform needs a specific, reliable answer to a narrow question, and building that answer on top of a full CSS parser would drag in far more than the plugin needs.

That design is what makes the plugin packs safe to compose. When several plugins in the same preset all need to look at the same `@media` list, they can all rely on one parser that the project maintains, instead of each shipping its own slightly different implementation. The cost is that the packages are a public surface too, and the `api-extractor.json` file at the root is the mechanism for tracking and reporting those APIs, which suggests the project treats the package API as something to be reviewed rather than incidental.

If you are writing your own PostCSS plugin and you find yourself reimplementing a tokenizer, this repository already has the one you want, and it is published as a standalone package.

Where the preset is the wrong tool

The limits of this approach are real and they are structural.

First, a transform is a compatibility guess, not a polyfill. When the preset rewrites a modern declaration into something an older browser understands, the output is a different value, and any feature that cannot be expressed in the old syntax is not transformed at all. The project says as much when it notes that it is not always possible. A colour function that cannot be approximated in an older syntax will simply not be rewritten, and the browser gets nothing. If your audience needs pixel-identical output, this approach will not give it to you.

Second, the stage system means silent surprises. Features are grouped by stage in CSSDB, and the preset decides what to do based on that grouping and on the browser targets you give it. Change your browser targets and you change the output, sometimes substantially, and the change is not visible in your source. A build that passes review on one target list can ship different CSS on another.

Third, the monorepo has a cost at the package level. Installing the preset pulls in a large dependency tree, and a project that only needs one transform inherits the whole graph. The individual plugins exist for that reason, but a hand-picked subset of plugins loses the coordination the pack provides, and the risk is duplicate or conflicting transforms when two of the selected plugins touch the same declaration.

Fourth, this is a moving target by design. The whole point of the CSSDB loop is that the catalogue changes as the spec moves, so the plugin set changes with it. That is a feature for a team that wants the transforms to track the spec and a liability for a team that wants a frozen, auditable build output, and the answer to the second case is to pin versions and re-test on each upgrade.

Editorial conclusion

Adopt postcss-preset-env when you support browsers that lack a CSS feature and want the transform maintained by the people who track the spec, rather than hand-writing fallbacks that go stale. Do not adopt the individual plugins piecemeal unless you know exactly which transforms you need, since the pack exists precisely to coordinate them. Check three things before you wire it in: that your build tool's PostCSS version matches what the plugins expect, that the `features` option you pass lists what you want enabled rather than leaving it to defaults, and that you remove autoprefixer from your config, because it is already part of the preset.

Frequently asked questions

How do I add postcss-preset-env to my build?

Install `postcss-preset-env` from npm and add it to the plugins list in your PostCSS configuration, passing a `features` object for the plugin options. The configuration in the project documentation also notes that you should remove autoprefixer if you had it, since it is part of postcss-preset-env.

Do I still need autoprefixer if I use postcss-preset-env?

No. The configuration example in the project documentation includes a comment telling you to remove autoprefixer if you had it in the plugin list, because it is part of postcss-preset-env. Keeping both means the same work runs twice.

What is CSSDB and how does it relate to these PostCSS plugins?

CSSDB is the catalogue of CSS features the project tracks, maintained in its own repository, and the plugins implement the transforms that bring that newer syntax to browsers that do not understand it. The project states that these plugins enable over 50 features, while noting that it is not always possible to convert every new feature.

What is in the csstools/postcss-plugins monorepo besides PostCSS plugins?

The workspace includes packages holding css tokenizers and parsers, such as css-tokenizer, css-parser-algorithms, css-calc, css-color-parser, cascade-layer-name-parser, and media-query-list-parser, plus Stylelint plugins under plugins-stylelint, CLI tools under cli, sites, and PostCSS recipes under postcss-recipes.

What licence are the csstools PostCSS plugins published under?

MIT-0, which is recorded in the root package.json and in the LICENSE.md file at the root of the repository. MIT-0 is the MIT licence without the requirement to keep the copyright notice.

Official sources

  1. csstools/postcss-plugins on GitHub
  2. Issues
  3. License: MIT-0
  4. Project website
  5. README
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/csstools-postcss-plugins.svg)](https://hysenlabs.com/projects/csstools-postcss-plugins)

Was this useful?