Tailwind CSS v4: CSS-First Config, Lightning CSS, and What Actually Changed
Everything you need to know about Tailwind CSS v4 — the new CSS-first @theme config, Lightning CSS engine, OKLCH color palette, and how to migrate from v3 without losing your mind.
If you have been putting off the Tailwind CSS v4 upgrade, let this be your sign to finally do it. v4 is not a minor version bump — it is a complete rethink of how Tailwind works. The new Lightning CSS engine shaves build times from seconds to microseconds. The CSS-first config system means tailwind.config.js is history. And features like container queries and 3D transforms are now built in, no plugins required. Let us break it all down.
What is Actually New in Tailwind v4
A New Engine: Lightning CSS
Tailwind v4 replaces the old PostCSS pipeline with Lightning CSS — a Rust-based CSS parser and transformer. The performance gains are not subtle:
Full rebuilds: 3.5x faster
Incremental builds: 8x faster
Already-compiled builds: 100x+ faster (we are talking microseconds)
If you have ever sat through a 2-second Tailwind rebuild during hot reload, this alone makes v4 worth it. The upgrade also means Tailwind handles more CSS transforms natively — vendor prefixing, modern syntax lowering — without extra PostCSS plugins.
CSS-First Configuration with @theme
This is the biggest mental shift in v4. Your design tokens — colors, fonts, spacing — no longer live in a JavaScript file. They live in CSS, using the @theme directive.
Here is what migrating a typical v3 config looks like:
// OLD: tailwind.config.js (v3)
module.exports = {
theme: {
extend: {
colors: {
brand: '#6366f1',
'brand-dark': '#4f46e5',
},
fontFamily: {
sans: ['Inter', 'sans-serif'],
},
borderRadius: {
'4xl': '2rem',
},
},
},
}/* NEW: your main CSS file (v4) */
@import "tailwindcss";
@theme {
--color-brand: #6366f1;
--color-brand-dark: #4f46e5;
--font-sans: 'Inter', sans-serif;
--radius-4xl: 2rem;
}The @theme block creates CSS custom properties that Tailwind uses to generate utility classes. You can now reference your design tokens directly in CSS with var(--color-brand), which was not easy to do in v3.
Setup Is Now One Line
In v3, bootstrapping Tailwind meant installing tailwindcss, postcss, and autoprefixer, creating tailwind.config.js, a PostCSS config, and specifying content paths. In v4:
/* styles.css */
@import "tailwindcss";
/* Done. */No content array. No config file unless you need custom tokens. Tailwind v4 auto-detects your template files by scanning the project directory. For Vite projects, use the dedicated plugin for best performance:
npm install tailwindcss@latest @tailwindcss/vite// vite.config.ts
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [
tailwindcss(),
],
})No PostCSS config needed when using the Vite plugin. It hooks directly into Vite's transform pipeline for maximum speed.
OKLCH Colors: Why Your UI Looks Better Now
Tailwind v4 switches the default color palette to OKLCH — a perceptually uniform color space. In plain English: the steps between color shades actually look even to the human eye, unlike old hex-based palettes where some steps looked way bigger than others. The blues and purples in the default palette are noticeably more vibrant.
@theme {
/* Perceptually uniform custom color scale */
--color-purple-500: oklch(0.627 0.265 303.9);
--color-purple-600: oklch(0.558 0.288 302.3);
--color-purple-700: oklch(0.491 0.270 302.5);
}Browsers support OKLCH natively now, so there is no transformation cost at runtime. Tailwind will still generate hex fallbacks for older browser targets if you configure them.
Breaking Changes: What Will Actually Break
Class Name Renames
v4 cleaned up a lot of inconsistent class names. The ones you will hit most often:
bg-gradient-to-r → bg-linear-to-r (and all gradient direction variants)
flex-shrink-0 → shrink-0
flex-grow → grow
overflow-ellipsis → text-ellipsis
decoration-clone → box-decoration-clone
shadow-sm is now the default shadow (old shadow is now shadow-xs)
Run the upgrade tool to handle these automatically:
npx @tailwindcss/upgradeIt handles about 90% of renames. The remaining 10% are usually project-specific patterns it cannot safely assume.
Dark Mode Behavior Changed
In v3, dark mode was configured in tailwind.config.js with darkMode: 'class'. In v4, you use @custom-variant in CSS:
/* v4 dark mode with class strategy */
@import "tailwindcss";
@custom-variant dark (&:where(.dark, .dark *));If you were using darkMode: 'media' in v3, that is now the default behavior in v4 — no extra configuration needed.
New Built-In Features (No Plugins Required)
Container Queries
Container queries let components respond to their container's size instead of the viewport. In v3 this required the @tailwindcss/container-queries plugin. In v4 it is built in:
<!-- Mark the container -->
<div class="@container">
<!-- Responds to container width, not viewport -->
<div class="grid grid-cols-1 @sm:grid-cols-2 @lg:grid-cols-4">
<!-- Cards that reflow based on their wrapper, not the window -->
</div>
</div>This is a game-changer for design systems. A card grid component that works correctly whether it is in a full-width layout or a sidebar — finally easy.
3D Transforms
Native 3D transform utilities ship in v4 with no plugin needed:
<div class="perspective-500">
<div class="rotate-x-12 transform-3d hover:rotate-x-0 transition-transform duration-300">
<!-- Actual 3D flip card effect -->
</div>
</div>Migration Checklist: v3 to v4
Run `npx @tailwindcss/upgrade` to auto-fix renamed classes
Replace @tailwind base/components/utilities with @import "tailwindcss"
Move theme.extend values from tailwind.config.js to @theme in CSS
Switch to the Vite plugin (@tailwindcss/vite) if you are on Vite
Update dark mode setup if you were using darkMode: 'class'
Remove @tailwindcss/container-queries plugin — it is built in now
Test your PostCSS pipeline — you may be able to remove autoprefixer
Verify shadow utilities — the scale shifted slightly in v4
TL;DR
Tailwind v4 uses Lightning CSS — builds are 3.5x to 100x faster
Config moves from tailwind.config.js to CSS @theme directives
Setup is one line: @import "tailwindcss"
OKLCH colors make your palette more vibrant and perceptually uniform
Container queries and 3D transforms are now built-in
Run npx @tailwindcss/upgrade to handle most of the migration
Dark mode config moves from JS to CSS @custom-variant
The migration is not zero effort but the upgrade tool gets you most of the way there. The CSS-first config is a better mental model once you are used to it — your design tokens live where they are used, not in a separate JS file. And the build speed improvements are the kind of quality-of-life upgrade that makes you wonder how you tolerated the old way.