CSS Tooling

PostCSS

PostCSS is a tool that transforms CSS with JavaScript plugins. It is the quiet engine behind Autoprefixer, Tailwind and most modern build pipelines.

intermediate12 min readUpdated Sep 15, 2026
postcss.config.js
js
// postcss.config.js
export default {
  plugins: {
    "postcss-import": {},
    "postcss-preset-env": { stage: 3 },
    autoprefixer: {},
    cssnano: {},
  },
};
What it is
A CSS transformer
Model
Plugins over an AST
Config
postcss.config.js
Runs in
Your build tool
Killer plugin
Autoprefixer
Fun fact
Tailwind is a PostCSS plugin

Why it matters

Why PostCSS matters

Future CSS today

Write modern syntax and let plugins translate it for the browsers your project actually supports.

Automatic vendor prefixes

Autoprefixer adds the right prefixes based on your browser targets, so you never write -webkit- by hand again.

Smaller production CSS

Optimisation plugins such as cssnano minify, merge and strip dead rules from the final bundle.

The big picture

The three parts of PostCSS

A parser, a plugin pipeline and a config file. PostCSS itself does almost nothing — the plugins do the work.

The parser

Read & rewrite

PostCSS parses CSS into an abstract syntax tree that plugins can walk and modify.

The plugins

Transform

Each plugin receives the tree, changes it, and passes it along the pipeline.

The build tool

Orchestrate

Vite, webpack and others run PostCSS automatically on every stylesheet you import.

PostCSS at a glance

The plugins you will meet

Autoprefixer

Adds vendor prefixes using your browserslist targets.

postcss-preset-env

Turns future CSS features into code browsers understand today.

postcss-nested

Lets you nest selectors before native nesting is available everywhere.

postcss-import

Inlines @import statements into a single stylesheet.

cssnano

Minifies and optimises the final output for production.

Custom plugins

Write a small plugin when you need a project-specific transformation.

A short history

How a CSS transformer became invisible infrastructure

  1. 2013

    PostCSS released

    Andrey Sitnik introduces a parser and plugin framework for transforming CSS.

    13
  2. 2014

    Autoprefixer goes mainstream

    The prefix plugin makes PostCSS part of nearly every front-end build.

    14
  3. 2015

    cssnext and preset-env

    Future CSS syntax becomes usable in production through a single plugin.

    15
  4. 2017

    Tailwind as a plugin

    Tailwind CSS is implemented as a PostCSS plugin, boosting the ecosystem further.

    17
  5. Today

    Invisible infrastructure

    PostCSS runs quietly inside Vite, Next.js, Angular and countless custom pipelines.

    Today

The complete guide

PostCSS: Everything you need to know

What is PostCSS?

PostCSS is a tool that transforms CSS with JavaScript plugins. On its own it does almost nothing. It parses your CSS into a tree, hands that tree to a list of plugins, and serialises the result back into CSS. The plugins are where all the behaviour lives.

That design is why PostCSS is everywhere. Autoprefixer, the plugin that adds vendor prefixes, is a PostCSS plugin. Tailwind CSS is a PostCSS plugin. cssnano, the minifier, is a PostCSS plugin. You are probably using PostCSS already without having installed it directly.

How it works

The pipeline has three stages.

  1. Parse. PostCSS reads a stylesheet and builds an abstract syntax tree (AST) — a structured representation of every rule, declaration, at-rule and comment.
  2. Transform. Each plugin walks the tree and mutates it. One plugin might add prefixes, another might inline imports, another might minify.
  3. Stringify. PostCSS writes the modified tree back out as CSS.

Because plugins operate on a tree rather than on text, they can make precise, safe changes. A plugin can insert a declaration, rename a selector or drop a rule entirely without brittle string replacement.

Configuration

PostCSS reads its plugin list from a config file in your project root. The modern format uses an object keyed by plugin name, and the order of keys is the order they run.

// postcss.config.js
export default {
  plugins: {
    "postcss-import": {},
    "postcss-preset-env": { stage: 3 },
    autoprefixer: {},
    cssnano: process.env.NODE_ENV === "production" ? {} : false,
  },
};

Setting a plugin to false disables it for that environment, which is how you keep minification out of development builds.

Autoprefixer

Autoprefixer is the plugin that made PostCSS famous. You write standard CSS and it adds the vendor prefixes your target browsers need, based on your browserslist configuration.

/* input.css */
.card {
  display: flex;
  user-select: none;
}

With sensible targets, Autoprefixer emits the -webkit- and -moz- variants automatically. As browser support changes, updating browserslist is enough — you never hand-edit prefixes again.

// package.json
{
  "browserslist": ["> 0.5%", "last 2 versions", "not dead"]
}

postcss-preset-env

postcss-preset-env bundles a curated set of plugins that let you write future CSS today. It covers nesting, custom media queries, :is() and :where(), logical properties and more, translating them based on your browser targets.

/* modern.css */
.card {
  color: oklch(70% 0.1 200);

  &:hover {
    color: oklch(75% 0.1 200);
  }
}

The stage option controls how experimental the accepted features are, from stage: 0 (very new) to stage: 4 (stable). A common choice is stage: 3.

Other useful plugins

  • postcss-import inlines @import statements into a single file, which reduces requests and lets bundlers see the whole graph.
  • postcss-nested adds Sass-like nesting for projects that cannot rely on native nesting yet.
  • cssnano minifies the output — it removes whitespace, merges rules, shortens colours and drops duplicates.
  • postcss-custom-media and postcss-custom-properties polyfill custom media and custom properties where needed.
  • stylelint shares the same AST and is often run alongside PostCSS for linting.

Integration with build tools

You rarely invoke PostCSS directly. Build tools run it for you.

  • Vite processes CSS through PostCSS automatically and picks up postcss.config.js.
  • Next.js ships PostCSS support and uses it for Tailwind and Autoprefixer.
  • Angular runs PostCSS internally for its component styles.
  • webpack uses postcss-loader in the CSS rule chain.

The practical upshot: add a config file and your existing imports get transformed with no other changes.

Writing a plugin

A plugin is a function that returns an object with a postcssPlugin name and a Once hook. The hook receives the root node and can walk it however it likes.

// postcss-uppercase-hex.js
export default function uppercaseHex() {
  return {
    postcssPlugin: "uppercase-hex",
    Declaration(decl) {
      decl.value = decl.value.replace(/#[0-9a-f]{3,8}/gi, (hex) => hex.toUpperCase());
    },
  };
}
uppercaseHex.postcss = true;

Register it in the config by importing the function instead of naming it as a string. Small plugins like this are a clean way to enforce project conventions across every stylesheet.

Plugin order

Plugins run in sequence, and each one sees the output of the last. A sensible order is:

  1. Imports first, so later plugins see one combined file.
  2. Syntax transforms such as postcss-preset-env and nesting next.
  3. Autoprefixer after the syntax is final, so prefixes match the actual output.
  4. Minification last, once nothing else will change.

Reversing the order can produce prefixes on syntax that later disappears, or a minified file that a later plugin then reformats.

When to use PostCSS

Use PostCSS when you want to write modern CSS and ship something your users’ browsers understand, when you need vendor prefixes without the maintenance, or when you want to optimise production CSS. If you already use Vite or Next.js, you are likely one config file away.

You may not need to think about it much if you use a framework that bundles it. But understanding the pipeline explains why your Tailwind classes appear, where the prefixes come from and how to add a transformation of your own.

Best practices

  • Define browserslist explicitly; it drives Autoprefixer and preset-env.
  • Keep the plugin list short and ordered intentionally.
  • Use postcss-import to combine files before other transformations.
  • Only enable cssnano in production.
  • Pin plugin versions and review upgrades, since transformations affect output.
  • Prefer native CSS features over plugins when browser support allows.
  • Write a small custom plugin instead of a fragile global find-and-replace.

Common mistakes

  • Expecting PostCSS to do something without any plugins configured.
  • Getting the plugin order wrong and losing prefixes or minification.
  • Leaving browserslist undefined, so plugins fall back to very broad defaults.
  • Running cssnano in development and making the CSS unreadable.
  • Treating PostCSS as a Sass replacement when the two solve different problems.
  • Adding many overlapping plugins and producing bloated, unpredictable output.

Where to go next

PostCSS is plumbing, but it powers the tools you use every day. See how it drives Tailwind CSS, how it complements Sass, and how Vite runs it automatically. With the CSS fundamentals in hand, you can shape the pipeline to fit any project.

Vendor prefixes

Autoprefixer derives the prefixes from your browser targets, so they stay correct as support changes.

With Autoprefixer
.card {
  display: flex;
  user-select: none;
}
/* output gains the needed
   -webkit- and -moz- rules */
By hand
.card {
  display: -webkit-box;
  display: -ms-flexbox;
  display: flex;
  -webkit-user-select: none;
  user-select: none;
}

Plugin order

Order matters. Run preset-env before Autoprefixer so prefixes are added to the final syntax.

Prefer
plugins: {
  "postcss-import": {},
  "postcss-preset-env": {},
  autoprefixer: {},
  cssnano: {},
}
Avoid
plugins: {
  cssnano: {},
  autoprefixer: {},
  "postcss-preset-env": {},
}

FAQ

Frequently asked questions

Keep learning

Related topics from the roadmap.

$ start learning

Ready to start learning PostCSS?

Our interactive tutorial walks you through PostCSS step by step — with quizzes and real code you can run in the browser.