Tailwind CSS v4 shipped in January 2025 and tailwind.config.js is gone. Configuration now lives inside the CSS file itself. I migrated a Next.js project — unfamiliar at first, but simpler once you're through it.
The actual transition is faster than expected. The official CLI handles about 80% of it.
What Changes
-
tailwind.config.js→ replaced by a CSS@themeblock - Rust-based Oxide compiler — up to 5x faster full builds, up to 100x faster incremental
- Automatic content detection — no more manual
contentarray -
@tailwind base/components/utilities→ single@import "tailwindcss" - Plugins declared in CSS via
@plugin "..."
Real-world number from Tailwind's own benchmark: a design system with 15,000 utility classes saw cold builds drop from 840ms to 170ms.
Config Moved into CSS
v3 kept everything in JS. v4 does it all in one CSS file.
/* v4 — configure directly in CSS */
@import "tailwindcss";
@theme {
--breakpoint-3xl: 1920px;
--color-brand: oklch(68% 0.19 245);
--font-display: "Inter Variable", sans-serif;
}
@theme uses CSS variables. Design tokens are visible in DevTools at runtime. One less JS dependency.
@theme Naming Convention
--color-{name}, --font-{name}, --spacing-{name}. Tailwind reads the namespace and generates utility classes automatically. Define --color-brand and text-brand, bg-brand, border-brand light up immediately.
Oxide Compiler
Rust, not Node. Replaces the old PostCSS plugin. Content path detection is automatic — no more content: ['./src/**/*.tsx']. Oxide ships inside the tailwindcss v4 package, no separate install. Integrates with Vite and PostCSS pipelines.
Migration Steps
Option A — one command
npx @tailwindcss/upgrade
Handles config conversion and class renames for projects without custom plugins.
Option B — manual (Next.js / PostCSS)
npm install tailwindcss@latest @tailwindcss/postcss
// postcss.config.js (v4)
module.exports = {
plugins: {
"@tailwindcss/postcss": {},
},
};
/* globals.css (v4) */
@import "tailwindcss";
@theme {
--color-brand: #6366f1;
}
tailwind.config.js can be deleted or kept — v4 doesn't read it. Deleting it is cleaner for team repos.
Plugins Now Live in CSS
@import "tailwindcss";
@plugin "@tailwindcss/typography";
@plugin "@tailwindcss/forms";
@plugin "./plugins/my-plugin.js";
@theme {
--color-brand: #6366f1;
}
The plugins array in tailwind.config.js is gone. Pass a package name or a file path to @plugin and it works. Existing addUtilities and addComponents APIs mostly still apply, but parts of the plugin API changed — verify behavior after migrating.
The outline-none Gotcha
v3: outline-none rendered as outline: 2px solid transparent — still accessible.
v4: outline-none renders as outline: none — actually removes the outline.
If you used outline-none to hide focus rings on buttons or inputs, swap in outline-hidden. Expect this to surface during accessibility checks.
v3 vs v4 at a Glance
| Area | v3 | v4 |
|---|---|---|
| Config | tailwind.config.js |
CSS @theme block |
| Import | three @tailwind lines |
@import "tailwindcss" |
| Content detection | manual array | automatic |
| Compiler | PostCSS (Node) | Oxide (Rust) |
| Plugins | plugins: [...] |
@plugin "..." |
outline-none |
transparent outline | actual none (use outline-hidden) |
Should You Upgrade Now?
- New project → v4. No reason not to.
- Existing v3 project → no rush. v3 is still supported.
- Heavy custom-plugin stack → stay on v3 until you've tested each plugin against the v4 API.
- Build times biting → v4 is worth the migration cost just for the Oxide numbers.
FAQ
Q. Do I need to delete tailwind.config.js?
No — v4 doesn't read it. The upgrade CLI handles conversion. Delete for cleanliness.
Q. Separate Oxide install?
No. Included in the tailwindcss v4 package.
Q. How long does migration take?
Small Next.js projects: 30 minutes including manual review. Larger ones with custom plugins and dynamic class composition (bg-${color}-500 patterns): a couple hours, because those aren't auto-migrated.
Sources
Originally published at GoCodeLab.
Top comments (0)