·6 min read

Tailwind v4 in production: what changed, what broke, what I would do differently

Six months and three production migrations with Tailwind v4. The Oxide engine is real, the PostCSS trap is real, and the CSS-first config grows on you faster than you expect.

CSSTailwindTooling

I migrated three production sites from Tailwind v3 to v4 over the last six months: this portfolio, a Next.js bookstore, and a dashboard at work. None of those migrations were trivial, none were disasters, and the result is genuinely better. Here is what changed, what broke, and what I would do differently if I started over.

The good

The Oxide engine is the headline feature and it lives up to it. Cold builds drop by 5x in my experience, hot rebuilds by 100x or more. On the dashboard, a save-to-paint cycle that used to take 800ms now takes about 12ms. You stop noticing Tailwind in the inner loop.

Configuration moves into CSS. Instead of tailwind.config.jswith a JS object describing colors and spacing, you write @theme blocks inside a CSS file. The first time I did this I thought it was a stylistic preference. After a month I think it is objectively better: your design tokens live next to your custom CSS, and the file is editable by anyone who knows CSS, not just people who know the Tailwind config API.

Container queries land as a first-class utility (@containerand @sm: variants), which is the feature I reach for most in new code. Layout that adapts to its parent instead of the viewport is a much better default than viewport breakpoints inherited from Bootstrap.

The annoying

PostCSS configuration is a trap. v4 ships its own engine and you must switch to @tailwindcss/postcss or the dedicated Vite plugin. If you leave the v3 tailwindcss plugin in postcss.config.js, your build silently produces no CSS and you spend an hour wondering why the page is unstyled. The docs say this clearly; the diagnostics do not.

The legacy purge and jit fields in tailwind.config.js are no longer read, but v4 will not warn you that they were ignored. If your safelist used to preserve dynamic classes, you need to move that list to the new @source inline() syntax or your color and animation classes get stripped silently.

Plugins are a mixed bag. Most of the big ones (Typography, Forms, Container Queries) ship v4-compatible releases. Smaller community plugins are hit or miss. If your project depends on more than two or three third-party plugins, audit them before you start the migration.

What I would do differently

Migrate one project as a spike, not the whole portfolio in a weekend. Pick the smallest meaningful surface, push it to production, watch the bundle and the visual diff for a week, then roll the playbook forward. I tried to do all three sites at once and regretted it on the second one when I hit a plugin incompatibility I had not seen in the spike.

Use the official upgrade tool (npx @tailwindcss/upgrade). It handles most of the v3-to-v4 syntax mechanically, including the renamed utilities (shadow-sm becomes shadow-xs, etc.), and surfaces the cases that need a human. Running it is faster than reading the migration guide twice.

Should you upgrade today

If you are starting a new project in 2026: yes, unconditionally. If you are on v3 in production: yes, but plan a week, not an afternoon. The CSS-first config and the build speed are worth the friction. The friction is real.