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.
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.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
tailwindcsspackage was a PostCSS plugin, but in v4 the PostCSS plugin lives in a dedicated@tailwindcss/postcsspackage."
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";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 autoprefixerDelete 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/vite3. 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(),
],
})4. Replace the old directives in your global 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#
npm run devA 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.jsno longer exists (or no longer referencestailwindcss/@tailwindcss/postcssif 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/viteto see which versions are actually installed side by side. - Check
package.jsondirectly:@tailwindcss/postcssshould no longer appear independenciesordevDependencies, and neither should a leftoverpostcssorautoprefixerentry 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
--forceto clear Vite's dependency cache: Vite caches its pre-bundled dependencies innode_modules/.vite, and re-bundling is only triggered by a lockfile change, a patches-folder change, a relevant field invite.config.ts, or aNODE_ENVchange — not by editingpostcss.config.json 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/viteas 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/postcssinpostcss.config.mjs:jsexport default { plugins: { '@tailwindcss/postcss': {}, }, }Removing
postcss-importandautoprefixerhere 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/postcssin the PostCSS config,@tailwinddirectives replaced with@import "tailwindcss";. -
Staying on Tailwind v3 intentionally: if a project depends on v3-only config (e.g. a JS-based
tailwind.config.jswith 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+autoprefixeras 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
Still stuck? Paste your error.
Paste the error message or stack trace — we check it against every fix and tool on the site.
Continue Reading
Fix slow Tailwind v3 in Vite: remove catch-all safelists
Separate oversized generated CSS from plugin cost, with a single-change compiler reproduction and an Autoprefixer negative control.
Fix shadcn "No Tailwind CSS configuration found" in Vite
What shadcn init actually looks for before it says Tailwind is missing, reproduced on Tailwind 3 and 4 with the one line that fixes each.
Fix Tailwind v4 IntelliSense not working in VS Code
Find which layer has stopped working: Tailwind project discovery, document mapping, or automatic suggestions inside JSX strings.


