DEV Community

Cover image for Fix: Tailwind PostCSS Plugin Has Moved (Vite + React)
Mahdi BEN RHOUMA
Mahdi BEN RHOUMA

Posted on Originally published at iloveblogs.blog

Fix: Tailwind PostCSS Plugin Has Moved (Vite + React)

TL;DR

If your Vite + React + TypeScript build fails with a PostCSS error about tailwindcss being used "directly as a PostCSS plugin," your project has Tailwind CSS v4 installed but a PostCSS config written for Tailwind v3. Since Tailwind CSS v4.0, the PostCSS plugin lives in a separate @tailwindcss/postcss package, and in a Vite project the officially recommended fix is to drop PostCSS entirely and use the dedicated @tailwindcss/vite plugin instead. Pick one integration path, not both.

The error

[plugin:vite:css] [postcss] It looks like you're trying to use `tailwindcss` directly
as a PostCSS plugin. The PostCSS plugin has moved to a separate package, so to
continue using Tailwind CSS with PostCSS you'll need to install `@tailwindcss/postcss`
and update your PostCSS configuration.
Enter fullscreen mode Exit fullscreen mode

This is the same error reported in a Stack Overflow question with 26,500+ views, tagged reactjs, tailwind-css, vite, postcss, and tailwind-css-4: a Vite + React + TS project on Tailwind CSS v4 that had both integration paths active at once: @tailwindcss/postcss in postcss.config.js and @tailwindcss/vite in vite.config.ts, on top of the pre-v4 @tailwind base/components/utilities directives still sitting in index.css. The question author had already tried uninstalling and reinstalling tailwindcss/postcss, swapping require('tailwindcss') for require('@tailwindcss/postcss') in the plugin array, and adding an extra @tailwindcss import — none of which fixed it, because the underlying problem was two competing integration paths registered at the same time, not a missing package. The error surfaces the moment Vite tries to process the CSS entry point, whether that happens on npm run dev or npm run build — it is a build-time PostCSS failure, not a runtime one, so the page never even reaches the browser while it's present.

Why it happens

In Tailwind CSS v3, the tailwindcss npm package doubled as a PostCSS plugin — you dropped tailwindcss: {} straight into postcss.config.js and it worked. The official Tailwind CSS v4 upgrade guide states this plainly:

"In v3, the tailwindcss package was a PostCSS plugin, but in v4 the PostCSS plugin lives in a dedicated @tailwindcss/postcss package."

That split happened in Tailwind CSS v4.0 (the first stable v4 release). The core tailwindcss package became build-tool agnostic, and each integration — PostCSS, Vite, the standalone CLI — moved into its own package (@tailwindcss/postcss, @tailwindcss/vite, @tailwindcss/cli). If your postcss.config.js still references tailwindcss as a plugin key while tailwindcss@4 is installed, PostCSS finds a package that no longer exposes a PostCSS plugin interface and throws this exact error.

The second, related trap in the same v4 upgrade: the @tailwind base;, @tailwind components;, @tailwind utilities; directives are deprecated in v4. The Vite installation guide replaces all three with a single line:

@import "tailwindcss";
Enter fullscreen mode Exit fullscreen mode

A project that fixes the PostCSS config but leaves the old @tailwind directives in index.css will hit a second, separate build failure — that's not a no-op detail, it's a distinct step.

Fix

The fastest fix for a Vite project is to stop using PostCSS for Tailwind altogether and use the dedicated Vite plugin, exactly as the official installation docs describe.

1. Remove the PostCSS-based Tailwind packages and config

npm uninstall @tailwindcss/postcss postcss autoprefixer
Enter fullscreen mode Exit fullscreen mode

Delete postcss.config.js (or postcss.config.mjs) entirely if Tailwind was its only reason to exist. If the file also configures something unrelated to Tailwind (a custom PostCSS plugin for a different concern), remove only the tailwindcss/@tailwindcss/postcss and autoprefixer entries from the plugins object instead of deleting the whole file — Tailwind v4 handles autoprefixing internally, so autoprefixer is redundant either way once you're on v4.

2. Install the core package and the Vite plugin

npm install tailwindcss @tailwindcss/vite
Enter fullscreen mode Exit fullscreen mode

3. Register the Vite plugin in vite.config.ts

import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite'

export default defineConfig({
  plugins: [
    react(),
    tailwindcss(),
  ],
})
Enter fullscreen mode Exit fullscreen mode

4. Replace the old directives in your global CSS

@import "tailwindcss";
Enter fullscreen mode Exit fullscreen mode

Remove @tailwind base;, @tailwind components;, and @tailwind utilities; — they are no longer valid entry points in v4.

5. Restart the dev server

npm run dev
Enter fullscreen mode Exit fullscreen mode

A stale Vite dependency cache is a common reason the error persists after the config is correct — if it still fails, clear node_modules/.vite and restart.

Verify the fix

  • Run npm run build. The [plugin:vite:css] [postcss] error should be gone.
  • Confirm postcss.config.js no longer exists (or no longer references tailwindcss/@tailwindcss/postcss if you kept PostCSS for another plugin).
  • Open the compiled page and confirm Tailwind utility classes (e.g. text-3xl font-bold) render styled, not as plain unstyled HTML.
  • Run npm ls tailwindcss @tailwindcss/vite to see which versions are actually installed side by side.
  • Check package.json directly: @tailwindcss/postcss should no longer appear in dependencies or devDependencies, and neither should a leftover postcss or autoprefixer entry unless something else in the project genuinely needs PostCSS.
  • If the dev server was already running when you made these changes, stop it fully (don't rely on hot reload) and restart it, or pass --force to clear Vite's dependency cache: Vite caches its pre-bundled dependencies in node_modules/.vite, and re-bundling is only triggered by a lockfile change, a patches-folder change, a relevant field in vite.config.ts, or a NODE_ENV change — not by editing postcss.config.js on its own.

Variants: Vite vs. Next.js vs. Create React App

The dedicated Vite plugin is the right call for Vite projects, but it doesn't apply everywhere:

  • Vite (Rollup-based, React/Vue/Svelte/SolidJS/SvelteKit): use @tailwindcss/vite as shown above. No PostCSS config needed.
  • Next.js: Next.js runs its own PostCSS pipeline internally, so there is no Vite plugin option — you keep @tailwindcss/postcss in postcss.config.mjs:
  export default {
    plugins: {
      '@tailwindcss/postcss': {},
    },
  }
Enter fullscreen mode Exit fullscreen mode

Removing postcss-import and autoprefixer here is safe too — Tailwind v4 handles imports and vendor prefixing internally, per the same upgrade guide.

  • Create React App / any plain PostCSS pipeline (webpack, esbuild via PostCSS loader): same as Next.js — @tailwindcss/postcss in the PostCSS config, @tailwind directives replaced with @import "tailwindcss";.
  • Staying on Tailwind v3 intentionally: if a project depends on v3-only config (e.g. a JS-based tailwind.config.js with plugins that aren't yet v4-compatible), pin the version explicitly instead of half-upgrading: npm install -D tailwindcss@3. The v3 PostCSS setup (tailwindcss + autoprefixer as plugin keys) is unchanged in that case.

If your project already has both a Vite config with tailwindcss() in plugins and a PostCSS config with @tailwindcss/postcss, that duplication is itself a bug — Tailwind ends up processing your CSS twice through two different pipelines, which is consistent with a build reporting the plugin-relocation error even after installing @tailwindcss/postcss, because the PostCSS branch is still wired in parallel to the Vite branch.

This same v3-to-v4 shift shows up in other build errors once the PostCSS plugin move is fixed — a mismatched @vitejs/plugin-react version or a broken Vite alias resolution are common next failures on the same upgrade path; see the fix for a missing @vitejs/plugin-react module and the fix for Rollup failing to resolve /src/main.tsx if either follows. If your tsconfig.json path aliases stop resolving after the same dependency cleanup, the compilerOptions.paths alias error fix covers that separately. Tailwind v4's architecture change is disruptive precisely because it touches the build pipeline rather than the utility classes themselves — the safest sequence is always to pick one integration (Vite plugin or PostCSS plugin), remove the other completely, and only then update the CSS entry point syntax.


Originally published at https://www.iloveblogs.blog

Top comments (0)