parcel-bundler/parcel · error · Error
PostCSS config must have plugins
Error message
PostCSS config must have plugins
What it means
Thrown by @parcel/transformer-postcss's config loader when the config object exists but contents.plugins is null, not an object, or is an empty object/array. PostCSS without plugins is meaningless (Parcel already does default transpilation), so the loader refuses to run an empty PostCSS config. Distinct from 135 which fires first for non-object top-level values.
Source
Thrown at packages/transformers/postcss/src/loadConfig.js:204
if (isDynamic) {
// We have to invalidate on startup in case the config is non-deterministic,
// e.g. using unknown environment variables, reading from the filesystem, etc.
logger.warn({
message:
'WARNING: Using a JavaScript PostCSS config file means losing out on caching features of Parcel. Use a .postcssrc(.json) file whenever possible.',
});
}
if (typeof contents !== 'object') {
throw new Error('PostCSS config should be an object.');
}
if (
contents.plugins == null ||
typeof contents.plugins !== 'object' ||
Object.keys(contents.plugins).length === 0
) {
throw new Error('PostCSS config must have plugins');
}
}
return configHydrator(
contents,
config,
configFile?.filePath,
options,
logger,
);
}
View on GitHub (pinned to 59484858a1)
Solutions
- Add at least one PostCSS plugin to the config (e.g. tailwindcss, postcss-preset-env, cssnano).
- If you do not need PostCSS plugins, delete the config file entirely — Parcel's default CSS pipeline already handles autoprefixing/transpilation.
- If only `postcss-modules` is used, set it under the `postcss-modules` key (the loader special-cases it before this check).
Example fix
// before: .postcssrc
{
"plugins": {}
}
// after (option a): add a plugin
{
"plugins": {
"tailwindcss": {}
}
}
// after (option b): delete .postcssrc and rely on Parcel defaults Defensive patterns
Strategy: validation
Validate before calling
function assertPostCSSPlugins(contents) {
if (!contents.plugins || typeof contents.plugins !== 'object' || Object.keys(contents.plugins).length === 0) {
throw new Error('PostCSS config needs at least one plugin — or delete the config to use Parcel defaults');
}
} Type guard
function hasPostCSSPlugins(contents) {
return Boolean(contents?.plugins) && typeof contents.plugins === 'object' && Object.keys(contents.plugins).length > 0;
} Prevention
- If you do not need PostCSS plugins, delete the config rather than leaving it empty.
- Review PostCSS configs in PRs to ensure at least one plugin remains.
When it happens
Trigger: A PostCSS config like `{ plugins: {} }`, `{ plugins: [] }`, or `{ }` (plugins key absent). The check is `contents.plugins == null || typeof contents.plugins !== 'object' || Object.keys(contents.plugins).length === 0`.
Common situations: Starting from a template and forgetting to fill in plugins; intentionally creating an empty config; copy-paste that drops the plugins block; using a JS config whose plugins assignment was commented out.
Related errors
- PostCSS config should be an object.
- Targets option is an empty array
- Could not find target with name "${target}"
- Missing distDir for target "${name}"
- Failed to parse package.json
AI-assisted analysis of parcel-bundler/parcel@59484858a1 (2026-08-13).
Data as JSON: /api/errors/3e70d40d40378d96.
Report an issue: GitHub.