Using PostCSS Nesting to Replace Sass: A Practical Build Guide
Learn how to add PostCSS nesting to your build pipeline, write nested CSS like Sass, and verify the output with minimal runtime overhead. Follow the step‑by‑step guide for Webpack or Vite.
14 Mar 2026, 21:36 UTC

Desired Outcome
The goal is to write CSS with nested rules that look like Sass or Less, but compile to flat, browser‑compatible CSS using the postcss-nesting plugin. The process should integrate cleanly into a modern build tool (Webpack, Vite, or any PostCSS‑aware bundler) and be easy to verify.
Prerequisites
- Node.js 14+ and npm or yarn installed.
- A project with an existing build tool (Webpack 5+, Vite 4+, or similar).
- Basic familiarity with CSS and the concept of an Abstract Syntax Tree (AST).
- Administrative or developer access to modify
package.jsonand configuration files.
Step 1 – Install PostCSS and the Nesting Plugin
Run the following command in the project root. The postcss package is the core engine, postcss-nesting implements the spec, and postcss-cli allows manual verification.
npm install --save-dev postcss postcss-nesting postcss-cli
Step 2 – Create postcss.config.js
PostCSS looks for this file at the project root. The plugin order matters: postcss-nesting must run before any plugin that expects regular CSS (e.g., autoprefixer).
module.exports = {
plugins: {
// 1️⃣ Nesting – transforms nested rules into flat selectors
"postcss-nesting": {},
// 2️⃣ Optional: Autoprefixer for vendor prefixes
"autoprefixer": {},
// 3️⃣ Optional: CSSNano for minification
"cssnano": { preset: "default" }
}
};
Step 3 – Integrate Into Your Build Tool
Webpack 5 Example
Use postcss-loader in the module.rules section.
module.exports = {
// ... other config
module: {
rules: [
{
test: /\.css$/,
use: [
"style-loader",
"css-loader",
{
loader: "postcss-loader",
options: {
postcssOptions: {
config: path.resolve(__dirname, "postcss.config.js")
}
}
}
]
}
]
}
};
Vite 4 Example
Vite automatically picks up postcss.config.js. If you need to add a custom CSS preprocessor, use the css.postcss option.
export default {
css: {
postcss: path.resolve(__dirname, "postcss.config.js")
}
};
Step 4 – Write Nested CSS
Create a src/styles.css file and use the & selector to refer to the parent.
/* src/styles.css */
.button {
padding: 0.5rem 1rem;
background: #0066cc;
color: white;
&:hover {
background: #005bb5;
}
&.primary {
background: #004499;
&:hover {
background: #003d7f;
}
}
}
Step 5 – Build and Verify
- Build with your tool. For Webpack:
npx webpack --mode production. For Vite:npm run build. - Verify the output. Open the generated CSS file (e.g.,
dist/styles.css) and confirm the nested rules are flattened:
.button { padding: 0.5rem 1rem; background: #0066cc; color: white; }
.button:hover { background: #005bb5; }
.button.primary { background: #004499; }
.button.primary:hover { background: #003d7f; }
Alternatively, run the PostCSS CLI directly to isolate the plugin:
npx postcss src/styles.css -o dist/flattened.css
Open dist/flattened.css in a browser or a text editor to check for syntax errors. In developer tools, you should see the selectors applied correctly.
Step 6 – Common Pitfalls & Recovery
- Plugin Order Error: If
postcss-nestingruns afterautoprefixer,autoprefixermay choke on the nested syntax and throw an error like "Unexpected token". Movepostcss-nestingto the top of the plugins list. - Over‑deep Nesting: Excessive nesting can generate selectors with high specificity, making overrides hard. Keep nesting to 2–3 levels and use classes or IDs for deeper scopes.
- Missing
postcss.config.js: If the file isn’t found, PostCSS falls back to defaults and will not apply the nesting transform. Ensure the file is at the project root and named exactlypostcss.config.js. - CLI vs Build Tool Mismatch: The CLI uses the config file automatically, but some bundlers may ignore it if they have an inline
postcssOptionsobject. Double‑check that the config path points to the correct file.
Recovery Checklist
- Run
npx postcss --helpto confirm the CLI is installed. - Check the console for errors during the build. The stack trace typically points to the plugin causing the issue.
- If the build succeeds but the CSS looks wrong, open the output CSS and compare it to the source. If selectors are missing, the nesting plugin may have been skipped.
- Reset the plugin order in
postcss.config.jsand rebuild.
Practical Takeaway
By configuring postcss-nesting as the first plugin and integrating it into your build tool, you can write clean, nested CSS without the runtime cost of a traditional pre‑processor. The flattened output ensures maximum browser compatibility, while the build process remains deterministic and easy to audit.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.