DEV Community

RAXXO Studios
RAXXO Studios

Posted on • Originally published at raxxo.shop

Tailwind CSS v4: What Changed and Why It Matters

  • Rust-powered Oxide engine cuts build times from ~3 seconds to under 1 second for faster development.

  • Design tokens now defined in CSS via @theme instead of tailwind.config.js for better organization.

  • Custom utilities created inline with @utility directive without needing plugins or complex configuration.

  • Automatic content detection eliminates manual file path configuration and related debugging issues.

  • CSS @layer organization ensures proper cascade without !important and prevents style conflicts automatically.

Tailwind v4 shipped with a completely rewritten engine, and the migration isn't just a version bump. After rebuilding RAXXO Studio's entire styling system on v4, here's what actually changed in practice - not the marketing overview, but the real differences you'll hit in daily development.

The Engine Rewrite

Tailwind v4 replaced the old JavaScript-based build system with a Rust-powered engine called Oxide. The practical impact: builds are significantly faster. On the RAXXO codebase, build times dropped from ~3 seconds to under 1 second. For hot module replacement during development, the difference is noticeable.

But speed isn't the main event. The engine change enabled new features that weren't possible with the old architecture.

CSS-First Configuration

The biggest conceptual shift: configuration moved from tailwind.config.js to CSS. Instead of a JavaScript config file, you define your design tokens directly in your CSS:

@theme {
  --color-brand: #e3fc02;
  --color-charcoal: #1f1f21;
  --font-display: "Outfit", sans-serif;
}
Enter fullscreen mode Exit fullscreen mode

This feels more natural than it sounds. Your design system lives in CSS where it belongs, and you can reference these tokens anywhere in your styles without importing JavaScript configuration.

The @utility Directive

Custom utilities used to require plugins. Now you define them inline:

@utility glass {
  backdrop-filter: blur(16px);
  background: rgba(31, 31, 33, 0.6);
  border: 1px solid rgba(255, 255, 255, 0.08);
}
Enter fullscreen mode Exit fullscreen mode

This creates a .glass class you can use in your HTML just like any built-in Tailwind utility. Responsive variants and state variants (hover, focus, etc.) work automatically.

Where @utility Falls Short

There's a gotcha that the documentation doesn't emphasize enough: @utility can't handle complex multi-layer backgrounds with background-blend-mode. If you're building layered glass effects (like the RAXXO design system's button styles), you need plain CSS classes instead.

The rule of thumb: if your style is a single property or a simple set of properties, use @utility. If it involves multiple interacting declarations with blend modes or animations, use a regular CSS class and keep it in your global stylesheet.

Automatic Content Detection

No more content array in your config telling Tailwind which files to scan. V4 detects your template files automatically based on your project structure. It reads your framework's configuration (Next.js, Vite, etc.) and figures out where your templates live.

This eliminates an entire category of "why isn't my class working?" bugs. If you've ever forgotten to add a file path to the content array and spent 20 minutes debugging why your styles aren't applying, you'll appreciate this change.

Native Cascade Layers

V4 uses CSS @layer to organize its output. Base styles, components, and utilities each live in their own cascade layer. This means Tailwind utilities always win over component styles without needing !important, and your custom component styles don't accidentally override base styles.

This is a subtle change that mostly helps when you're mixing Tailwind with other CSS. For the RAXXO design system, where custom glass classes coexist with Tailwind utilities, the explicit layering makes specificity predictable.

Container Queries Built In

Container queries are first-class in v4:

<div class="@container">
  <div class="@md:grid-cols-2 @lg:grid-cols-3">
    ...
  </div>
</div>
Enter fullscreen mode Exit fullscreen mode

Components that respond to their container's size rather than the viewport size. This is huge for reusable components that might appear in different layout contexts - a card that should be full-width in a sidebar but multi-column in a main content area.

New Color System

The color palette got a refresh with better perceptual uniformity. More importantly, v4 supports wide-gamut colors natively. If you're designing for modern displays (which you should be), you can use OKLCH and P3 colors directly:

@theme {
  --color-brand: oklch(0.91 0.2 128);
}
Enter fullscreen mode Exit fullscreen mode

The RAXXO brand green (#e3fc02) is particularly vivid on P3 displays, and v4 makes it easy to serve the best possible color to each device.

Migration Gotchas

Real issues I hit during the v3 to v4 migration:

  • Config file changes: tailwind.config.js still works for compatibility, but some options moved. Check the migration guide for your specific config options.

  • Plugin compatibility: not all v3 plugins work with v4. Check each plugin's compatibility before upgrading.

  • PostCSS setup: the PostCSS plugin changed from tailwindcss to @tailwindcss/postcss. Update your PostCSS config.

  • Class name changes: some utility class names changed. bg-opacity-50 became bg-black/50 in v3 already, but v4 removes more deprecated patterns.

  • Dark mode: the class strategy now uses the CSS color-scheme property. If you were toggling dark mode with a class, verify it still works.

Should You Upgrade?

For new projects: absolutely. V4 is the better foundation.

For existing projects: it depends on complexity. A small marketing site - upgrade in an afternoon. A large application with custom plugins and extensive configuration - plan for a more methodical migration. The Tailwind team provides a migration tool that handles most automated changes.

For RAXXO Studio, the upgrade was worth it for the build speed improvement alone. The new @utility directive simplified the design system code significantly, and the CSS-first configuration makes the styling feel more cohesive. The couple of hours spent on migration paid back in days.

Top comments (0)