Migrating to Tailwind CSS v4: The Oxide Engine, CSS-First Config, and an 8x Faster Build
By Arash Latifi
Tailwind v4 drops the JavaScript config for a CSS-first @theme block and ships a Rust-based Oxide engine that builds ~8x faster. Step-by-step v3→v4 migration guide with comparison tables, code, and pitfalls.
TL;DR: Tailwind v4 swaps its engine for Oxide (written in Rust), making cold builds up to 8x faster and HMR updates ~96% faster. The big change for you:
tailwind.config.jsis gone — configuration now lives in CSS via the@themeblock. Utility class names barely changed, so the migration is mostly about plugins and config, not HTML. You can finish it in ~10 minutes.
When Tailwind v4 dropped, most of us assumed "just another version bump." It isn't. The configuration philosophy flipped. If you're still on v3, this one's for you — metaphor and code, no jargon.
Why Upgrade at All? — Before/After
Oxide isn't "a bit faster." It's an order of magnitude different. Real numbers from migrated projects:
| Metric | v3 | v4 (Oxide) | Improvement | |---|---|---|---| | Cold build | ~12.3s | ~1.8s | ~8x faster | | Dev server start | ~4.2s | ~0.8s | ~81% faster | | HMR update | ~340ms | ~12ms | ~96% faster | | Production CSS | ~48KB | ~31KB | ~35% smaller | | Memory usage | ~180MB | ~45MB | ~75% less |
The analogy is simple: v3 re-ran a whole workshop each time to count which classes were used; v4's Rust engine does that counting in milliseconds. On a big project, the "hit F5 and wait" feeling is gone.
The Roadmap: 6 Steps
Step 1 — Update dependencies
If you use @tailwindcss/vite, remove the old plugin from vite.config.ts and add this:
Step 2 — Swap the @tailwind directives
Step 3 — Move config into CSS (the big one!)
Your custom color lived in a JS object in v3:
In v4 it becomes real CSS — via the @theme block:
Two things to note:
- Names are flattened: old
colors.brand.lightis now--color-brand-light, not--color-brand.light. - These are real CSS variables: usable outside Tailwind — in inline styles, arbitrary values, even
getComputedStylein JS.
Step 4 — Load plugins with @plugin
Step 5 — Fix dark mode
In v3 you wrote darkMode: "class". v4 defaults to prefers-color-scheme; for class strategy:
Step 6 — Declare non-standard paths with @source
Content outside default scan paths (e.g. a file in another package):
Quick Comparison: What Changed?
| Topic | v3 | v4 |
|---|---|---|
| Engine | PostCSS + JS | Rust (Oxide) |
| Config | tailwind.config.js | CSS @theme |
| Plugins | require in config | @plugin in CSS |
| Custom classes | @layer utilities | @utility |
| Container Queries | separate plugin | built-in (@container) |
| corePlugins | available | removed |
| theme() | JS function | use CSS vars |
| Utility class names | — | almost unchanged |
Pitfalls You'll Hit
1. @layer utilities no longer works. Your custom class used to live inside @layer utilities so it picked up variants like hover: and lg:. In v4 use @utility:
2. Drop the theme() function. Instead of theme("colors.primary"), use var(--color-primary).
3. Third-party plugins, not you, are the risk. Real-world migrations show the cost lives in plugins, not templates. Audit your plugin list for v4-compatible versions first — one stale plugin breaks the rest.
4. Nested color objects. If you had colors.brand.light, flatten it: --color-brand-light.
FAQ
Q: Will my current classes (flex, text-sm, bg-red-500) break?
A: No. Utility names are nearly unchanged; most v3 templates compile under v4 with zero HTML edits. The real work is config and plugins.
Q: Can I run v3 and v4 side by side?
A: Not cleanly. v4 is a deliberate breaking change; migrate in one shot. For very large projects a staged migration with @source is possible but more painful.
Q: Is tailwind.config.js fully gone?
A: It still exists for advanced cases, but the recommended path is CSS-first; config is no longer the source of truth for design tokens.
Q: Why is the CSS output smaller? A: The new engine cuts old overhead, and since the theme is generated as CSS variables, duplication disappears.
Q: What about Next.js?
A: On Next.js 15+ use @tailwindcss/postcss: @import "tailwindcss" in your main CSS file and the PostCSS plugin in postcss.config.mjs.
Wrap-up
Migrating to Tailwind v4 means accepting a big philosophical shift: config moved from JavaScript to CSS, and the engine moved from JavaScript to Rust. The payoff is practical: faster builds, near-instant HMR, leaner CSS. With the 6 steps and checklist above you can move your project in one short working session — just watch the plugins.