Tailwind CSS v4: What's New and How to Migrate
·PkgPulse Team
TL;DR
Tailwind CSS v4 is a complete rewrite with a new engine, CSS-first configuration, and zero config files. The Rust-based engine (Lightning CSS) makes full rebuilds 5x faster and incremental builds 100x faster. The big DX change: tailwind.config.js is gone — configuration now happens in your CSS file. Most utility class names stayed the same; the breaking changes are in configuration syntax and a handful of renamed utilities. For existing projects, the official upgrade tool handles ~80% of the migration automatically.
Key Takeaways
- New engine: Rust-based (via Lightning CSS) — 5x faster full builds, 100x faster incremental
- No more tailwind.config.js — all configuration is now in CSS with
@theme - CSS-first config: define custom colors, fonts, spacing in your CSS file, not a JS config
- Zero PostCSS config needed — v4 is a standalone binary with the Vite plugin
- Breaking changes: some utility names changed; config format changed entirely
What's New: The Engine Rewrite
# Build speed comparison (same project, 450 utility classes):
Tailwind CSS v3 (PostCSS):
Full build: ~800ms
Incremental: ~180ms
Dev (first load): ~600ms
Tailwind CSS v4 (Lightning CSS):
Full build: ~150ms (5.3x faster)
Incremental: ~2ms (90x faster)
Dev (first load): ~80ms
# Real impact:
# → Cold CI builds: seconds saved per build
# → Dev hot reload: imperceptible (was already fast, now instant)
# → Large projects with 1000+ utility classes: most noticeable improvement
# Installation (v4 is a standalone package, no PostCSS required):
npm install tailwindcss@next @tailwindcss/vite@next
# vite.config.ts:
import tailwindcss from '@tailwindcss/vite';
export default {
plugins: [
tailwindcss(),
],
}
# That's it. No tailwind.config.js. No postcss.config.js.
# Add to CSS:
# @import "tailwindcss";
CSS-First Configuration: The Big Change
/* Tailwind v3 — configuration in tailwind.config.js:
module.exports = {
theme: {
extend: {
colors: { brand: '#5B21B6' },
fontFamily: { display: ['Inter', 'sans-serif'] },
}
}
}
*/
/* Tailwind v4 — configuration IN your CSS file: */
@import "tailwindcss";
@theme {
/* Custom colors — these become Tailwind utilities automatically */
--color-brand: #5B21B6;
--color-brand-light: #7C3AED;
--color-brand-dark: #4C1D95;
/* Custom fonts */
--font-family-display: "Inter", sans-serif;
/* Custom spacing */
--spacing-18: 4.5rem;
/* Custom breakpoints */
--breakpoint-xs: 475px;
/* Custom animations */
--animate-wiggle: wiggle 1s ease-in-out infinite;
}
/* After this, you can use:
bg-brand, text-brand, border-brand
font-display
p-18, m-18, gap-18
xs:grid-cols-2
animate-wiggle
*/
/* Advantages of CSS-first config:
→ No JS tooling to parse the config (faster)
→ CSS variables are real CSS custom properties
(they cascade! You can scope them to a component)
→ Dark mode via CSS variables is cleaner */
/* Scoped theme overrides: */
.high-contrast {
--color-brand: #000000;
/* All brand-* utilities in this scope use black */
}
Renamed and Changed Utilities
<!-- Changes from v3 to v4 -->
<!-- Shadows: opacity-based syntax removed -->
<!-- v3: -->
<div class="shadow-black/50">...</div>
<!-- v4: same, still works ✅ -->
<!-- Border radius: renamed for clarity -->
<!-- v3: rounded-sm, rounded, rounded-md, rounded-lg, rounded-xl, rounded-2xl -->
<!-- v4: rounded-sm → rounded-xs (the old sm is now the default "rounded") -->
<!-- Blur: renamed similarly -->
<!-- v3: blur-sm = 4px, blur = 8px, blur-md = 12px -->
<!-- v4: blur-xs = 4px, blur-sm = 8px, blur = 12px -->
<!-- Ring offset: now part of ring utilities -->
<!-- v3: ring-offset-2 ring-offset-white -->
<!-- v4: ring-2 ring-offset-2 (ring-offset-color via CSS variable) -->
<!-- Placeholder color: -->
<!-- v3: placeholder-gray-400 -->
<!-- v4: placeholder:text-gray-400 (uses variant syntax) -->
<!-- Caret color: -->
<!-- v3: caret-blue-500 -->
<!-- v4: still works ✅ -->
<!-- The full list is shorter than you'd expect.
Most utility names are unchanged.
The config format is the bigger migration. -->
Migration: Using the Official Tool
# The official upgrade tool (handles ~80% automatically):
npx @tailwindcss/upgrade@next
# What it does:
# 1. Detects your current Tailwind version
# 2. Updates package.json dependencies
# 3. Migrates tailwind.config.js → @theme block in CSS
# 4. Renames changed utilities in your HTML/JSX/TSX files
# 5. Updates postcss.config.js to remove tailwind-specific config
# After running the tool, manually check:
# → Custom plugins (v4 has a new plugin API)
# → JIT mode settings (always-on in v4, nothing to configure)
# → Safelist patterns (moved to @source in CSS)
# → Prefix configuration (now @import "tailwindcss" prefix-my-prefix)
# Manual migration for plugins:
# v3 plugin:
module.exports = {
plugins: [
plugin(function({ addUtilities }) {
addUtilities({
'.clip-circle': { 'clip-path': 'circle(50%)' },
});
}),
],
}
# v4 plugin (in CSS):
@plugin "@tailwindcss/forms";
# v4 custom utilities:
@utility clip-circle {
clip-path: circle(50%);
}
# Use with: class="clip-circle"
Dark Mode: Cleaner With CSS Variables
/* v3 dark mode (class strategy):
You had: .dark { ... }
Tailwind applied dark: variants based on .dark class on <html>
*/
/* v4 dark mode is the same by default, but CSS variables make it cleaner: */
@theme {
--color-background: #ffffff;
--color-foreground: #000000;
--color-card: #f9fafb;
}
@media (prefers-color-scheme: dark) {
:root {
--color-background: #0a0a0a;
--color-foreground: #ffffff;
--color-card: #1a1a1a;
}
}
/* OR with class strategy for user toggle: */
.dark {
--color-background: #0a0a0a;
--color-foreground: #ffffff;
}
/* Then use: */
<div class="bg-background text-foreground">
<!-- These respond to the CSS variable, no Tailwind dark: needed -->
</div>
/* This is how shadcn/ui works — and it's cleaner than dark:bg-gray-900 everywhere */
Should You Upgrade Now?
Tailwind CSS v4 status (2026):
→ v4.0 released in early 2025
→ Ecosystem tooling (shadcn, Headless UI, etc.) has v4 support
→ PostCSS plugin still works if you need it (not recommended for new projects)
Upgrade timing:
New project: → Start on v4. No reason to use v3 for new projects.
Existing v3 project → Run the upgrade tool, test, migrate.
Most projects: 2-4 hours including manual fixes.
Large codebase: → Schedule a full day. Test thoroughly.
Custom plugins need manual rewriting.
Risk assessment:
Low risk: Basic Tailwind usage (no custom plugins, standard utilities)
Medium risk: Custom plugin usage, extended theme with many values
Higher risk: Heavy use of the JS config API, complex plugin ecosystem
The 5x build speed improvement alone makes v4 worth it for large projects.
For small projects, the DX improvement (no config file) is the main benefit.
Recommendation:
→ New projects: v4 immediately
→ Existing v3 projects: migrate when you have a focused sprint for it
→ Don't delay — v3 will enter maintenance mode
Track Tailwind CSS download trends and version adoption at PkgPulse.
See the live comparison
View tailwindcss v4 vs. v3 on PkgPulse →