TypeScript

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

The exact steps to resolve the Tailwind v4 PostCSS plugin relocation error in a Vite + React + TypeScript build.

Mahdi Ben RhoumaMahdi Ben Rhouma
7 min read

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#

plaintext
[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.

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:

css
@import "tailwindcss";

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#

bash
npm uninstall @tailwindcss/postcss postcss autoprefixer

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#

bash
npm install tailwindcss @tailwindcss/vite

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

ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite'
 
export default defineConfig({
  plugins: [
    react(),
    tailwindcss(),
  ],
})

4. Replace the old directives in your global CSS#

css
@import "tailwindcss";

Remove @tailwind base;, @tailwind components;, and @tailwind utilities; — they are no longer valid entry points in v4. If that CSS also applies shadcn/ui colours such as @apply border-border from your tailwind.config.js, v4 no longer reads that file on its own: Fix "Cannot apply unknown utility class border-border" shows the @config line that loads it.

5. Restart the dev server#

bash
npm run dev

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.

One email a month — the latest explained errors

What the site published that month — mostly Next.js, Supabase and Node errors, explained. You confirm by email; unsubscribe any time in one click.

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:

    js
    export default {
      plugins: {
        '@tailwindcss/postcss': {},
      },
    }

    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.

Further reading: Fix shadcn "No Tailwind CSS configuration found" in Vite. Also see Fix slow Tailwind v3 in Vite: remove catch-all safelists. Also see Tailwind CSS not working after Vite build: dev vs dist.

Frequently Asked Questions

|

Have more questions? Contact us

Still stuck? Paste your error.

Paste the error message or stack trace — we check it against every fix and tool on the site.

Matching happens in your browser. When you search, a cleaned error signature is sent so we can spot errors we do not cover yet — never the raw text, your IP address or your e-mail. Do not paste passwords or keys. Details

Written by

Mahdi Ben Rhouma
Mahdi Ben Rhouma

Full-Stack Dev — Next.js & Supabase

Solo developer building SaaS products with Next.js and Supabase. Writing about production patterns the official docs skip.

Remote