Tailwind CSS 4 Migration: What Changed & How to Upgrade
DesignRevision Editorial
· SaaS, frontend & developer tooling
Tailwind CSS 4 is the biggest update in the framework's history, and it has had time to settle: the line is on 4.3.3 as of July 2026.
It replaces the JavaScript-based build system with a Rust-powered engine, moves configuration from JavaScript files to native CSS, and cuts full build times to roughly a quarter of v3.
If you've been writing Tailwind for years, the upgrade changes how you think about configuration.
And if you're starting fresh, tailwind 4 is simply a better starting point.
This guide covers every major change, the complete migration path from v3, and the framework-specific setup for Next.js and Vite projects.
Key Takeaways
If you remember nothing else:
- Tailwind 4 replaces
tailwind.config.jswith CSS-first configuration using the@themedirective and CSS custom properties- The new Oxide engine (built in Rust) is measurably faster. On Tailwind's own Catalyst benchmark a full build drops from 378ms to 100ms, and an incremental rebuild that adds no new CSS goes from 35ms to 192µs
- The entry point changes from
@tailwind base/components/utilitiesto@import "tailwindcss"- Content detection is automatic in tailwind 4. No more manual
content: [...]arrays in config- New features include native container queries, 3D transforms,
color-mix()support, and CSS cascade layers- The official upgrade tool (
npx @tailwindcss/upgrade) automates most migration steps- PostCSS setup changes: replace
tailwindcssplugin with@tailwindcss/postcss, or use the new@tailwindcss/viteplugin
Table of Contents
- Why Tailwind 4 Is a Major Rewrite
- The Oxide Engine: Performance Gains
- CSS-First Configuration: Goodbye tailwind.config.js
- New Features in Tailwind 4
- Breaking Changes: What Moved, Changed, or Disappeared
- Step-by-Step Migration Guide
- Framework-Specific Setup
- Plugin Compatibility
- Before and After: Code Comparisons
- Common Migration Errors and Fixes
- Should You Upgrade Now?
- Conclusion
Why Tailwind 4 Is a Major Rewrite
Tailwind CSS v3 was built on a JavaScript engine that processed your configuration file, scanned your templates, and generated CSS.
It worked, but the architecture had limits.
Build times scaled poorly on large projects.
Configuration lived in JavaScript, separate from the CSS it produced.
And the content scanning system required manual file path configuration that broke in monorepos.
Tailwind 4 rewrites the core from scratch.
The JavaScript engine is replaced by Oxide, a Rust-based compiler that processes CSS natively.
Configuration moves from tailwind.config.js into your CSS files using standard CSS syntax.
Content detection becomes automatic, scanning your project without manual path configuration.
The result is a framework that is faster, simpler to configure, and more aligned with how CSS actually works.
So tailwind css 4 isn't a minor version bump with new utilities.
It's a foundational change in how the tool operates.
The Oxide Engine: Performance Gains
The headline improvement in tailwind 4 is raw speed.
The Oxide engine replaces the JavaScript-based build pipeline with a Rust compiler that processes CSS directly.
Build Time Benchmarks
These are the figures Tailwind published with the v4.0 release, measured on their own Catalyst template:
| Metric | v3.4 | v4.0 | Improvement |
|---|---|---|---|
| Full build | 378ms | 100ms | ~3.8x faster |
| Incremental rebuild, new CSS | 44ms | 5ms | ~8.8x faster |
| Incremental rebuild, no new CSS | 35ms | 192µs | ~182x faster |
Look at that third row, because it's the one you feel every day.
Most of the time you're reusing classes that already exist in your CSS: flex, p-4, font-bold.
In v3 that still cost 35ms of rebuild.
In v4 it's measured in microseconds, which is why HMR in v4 feels like nothing is happening at all.
For a small project with a few hundred classes, the full-build difference is marginal.
For a production app with thousands of classes across hundreds of files, it changes how the dev server feels.
Why Rust Matters
Where does the speed come from? Three architectural changes:
- Native CSS parsing. Oxide reads and generates CSS without converting to and from JavaScript ASTs. This eliminates the serialization overhead that slowed v3
- Parallel processing. Rust enables multi-threaded scanning of source files. Large codebases benefit from parallel content detection
- Zero-runtime JavaScript. The build process produces pure CSS without any runtime JavaScript. No more PostCSS plugin chain for Tailwind processing
And for teams running v4 alongside other build tools, the smaller build footprint means faster CI pipelines and quicker dev server startup.
CSS-First Configuration: Goodbye tailwind.config.js
The most significant workflow change in tailwind v4 is the move from JavaScript configuration to CSS-first configuration.
Instead of defining your design system in tailwind.config.js, you define it directly in your CSS using the @theme directive.
The @theme Directive
The @theme directive replaces the theme and extend sections of your JavaScript config.
Every value you define becomes a CSS custom property, making your design tokens available throughout your stylesheets.
Tailwind v3 configuration:
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
primary: '#3B82F6',
secondary: '#10B981',
},
fontFamily: {
sans: ['Inter', 'sans-serif'],
mono: ['JetBrains Mono', 'monospace'],
},
spacing: {
'18': '4.5rem',
'112': '28rem',
},
},
},
}
Tailwind 4 configuration:
@import "tailwindcss";
@theme {
--color-primary: #3B82F6;
--color-secondary: #10B981;
--font-sans: "Inter", sans-serif;
--font-mono: "JetBrains Mono", monospace;
--spacing-18: 4.5rem;
--spacing-112: 28rem;
}
The CSS approach has concrete advantages beyond simplicity.
Your design tokens are native CSS custom properties, accessible from any stylesheet without Tailwind-specific tooling.
IDE autocompletion works out of the box.
And there's no JavaScript build step sitting between your configuration and your CSS output.
The @import Entry Point
The entry point for tailwind css 4 changes from three directives to a single import:
v3:
@tailwind base;
@tailwind components;
@tailwind utilities;
v4:
@import "tailwindcss";
This single import handles base styles, component layer, and utilities.
The framework uses native CSS cascade layers internally to maintain the correct specificity order.
Automatic Content Detection
Remember the content array? It was one of the most frustrating things about v3.
You had to manually list every file path that contained Tailwind classes.
Miss a path and your classes got purged.
Monorepos required complex glob patterns.
Version 4 gets rid of the content array entirely.
The Oxide engine automatically detects which files contain Tailwind classes by scanning your project.
No configuration needed.
And no broken builds because you forgot to add a directory.
If you need to explicitly include or exclude paths, you can use the @source directive:
@import "tailwindcss";
@source "../shared-components/**/*.tsx";
But for most projects, automatic detection just works.
If you have been using our Tailwind cheat sheet as a reference, the utility class names remain the same.
The change is only in how the build tool finds them.
New Features in Tailwind 4
Beyond the architectural rewrite, tailwind 4.0 introduces utilities and capabilities that were previously impossible or required plugins.
Container Queries
Native container query support lets you style elements based on their parent container's size rather than the viewport.
It's been the most requested feature for responsive component design for years.
<div class="@container">
<div class="grid @sm:grid-cols-1 @lg:grid-cols-2 @xl:grid-cols-3">
<div class="p-4">Responsive to container, not viewport</div>
</div>
</div>
Container queries make components genuinely portable.
A card component adapts its layout based on where it is placed, whether that is a narrow sidebar or a wide main content area.
3D Transforms
New transform utilities support 3D space without custom CSS:
<div class="perspective-[1000px]">
<div class="rotate-x-12 rotate-y-6 translate-z-8 transform-3d">
3D transformed element
</div>
</div>
Utilities include rotate-x-*, rotate-y-*, translate-z-*, perspective-*, and transform-3d (which maps to transform-style: preserve-3d) for building card flips, parallax effects, and interactive 3D interfaces.
color-mix() Support
The color-mix() function enables dynamic color blending directly in utility classes:
<div class="bg-[color-mix(in_srgb,var(--color-primary)_70%,white)]">
70% primary, 30% white
</div>
It's particularly useful for hover states, disabled states, and colour variations you'd otherwise define shade by shade.
CSS Cascade Layers
The framework uses native CSS @layer for organizing styles in v4, registering four layers in this order:
@layer theme, base, components, utilities;
Your custom styles integrate into that system naturally:
@import "tailwindcss";
@layer components {
.btn {
@apply px-6 py-3 rounded-lg font-medium;
}
.card {
@apply bg-white rounded-xl shadow-sm border border-gray-200;
}
}
Cascade layers guarantee that utilities always override component styles regardless of source order, eliminating a class of specificity bugs that plagued v3 projects.
Native CSS Variables Everywhere
Every theme value in v4 is a CSS custom property.
This means you can access your design tokens from any CSS context, not just through utility classes:
.custom-element {
background: var(--color-primary);
font-family: var(--font-sans);
padding: var(--spacing-4);
}
So this bridges the gap between utility-first and traditional CSS.
You get the design system consistency of Tailwind with the flexibility of custom CSS when you need it.
Improved Gradient APIs
Gradient utilities are more flexible with support for gradient angles, multiple color stops with positions, and interpolation methods:
<div class="bg-linear-to-r from-blue-500 from-20% via-purple-500 via-60% to-pink-500">
Gradient with explicit stop positions
</div>
Breaking Changes: What Moved, Changed, or Disappeared
Every major version introduces breaking changes.
But this one changes more than most, because the architecture moved underneath it.
Here's what you need to know before migrating.
Browser Support: Check This First
Before anything else, check this one, because no upgrade tool can fix it.
Tailwind CSS v4 is designed for Safari 16.4+, Chrome 111+, and Firefox 128+.
The rewrite leans on modern CSS: cascade layers, @property, color-mix().
And those aren't polyfillable the way a missing utility class is.
So if your analytics show meaningful traffic from older browsers, that's your blocker.
Not plugins, not config.
Everything else in this guide is a migration task.
This one is a product decision.
Stay on v3.4 if you can't drop those browsers.
It's still maintained on the v3-lts tag.
Configuration Changes
| What Changed | v3 | v4 |
|---|---|---|
| Config file | tailwind.config.js (required) |
@theme in CSS (recommended) |
| Entry point | @tailwind base/components/utilities |
@import "tailwindcss" |
| Content paths | content: ['./src/**/*.tsx'] |
Automatic detection |
| PostCSS plugin | tailwindcss |
@tailwindcss/postcss |
| Vite integration | PostCSS plugin | @tailwindcss/vite plugin |
| CLI | npx tailwindcss |
npx @tailwindcss/cli |
Renamed and Updated Utilities
| v3 Utility | v4 Equivalent | Notes |
|---|---|---|
bg-gradient-to-r |
bg-linear-to-r |
Aligns with CSS linear-gradient naming |
bg-opacity-* |
bg-{color}/{opacity} |
Uses slash syntax: bg-blue-500/75 |
text-opacity-* |
text-{color}/{opacity} |
Same pattern as background |
decoration-slice |
box-decoration-slice |
Full CSS property name |
decoration-clone |
box-decoration-clone |
Full CSS property name |
flex-shrink-* |
shrink-* |
Simplified (already in late v3) |
flex-grow-* |
grow-* |
Simplified (already in late v3) |
overflow-ellipsis |
text-ellipsis |
Renamed for clarity |
Default Changes
- Default border color changed from
gray-200tocurrentColor, matching the CSS specification default - Default ring width changed from
3pxto1px, and the default ring color changed fromblue-500tocurrentColor. If you used bareringfor focus states, they will now be thinner and a different colour - Color scale uses updated values. If your design depends on exact hex values from v3 defaults, verify them after migration
- Dark mode defaults to
mediastrategy. Switch toclassstrategy via CSS if you use manual dark mode toggling
What Was Removed
- The standalone
tailwindcssPostCSS plugin. Use@tailwindcss/postcssinstead - The
tailwindcss initcommand. Configuration lives in CSS now - The
contentconfiguration array. Replaced by automatic detection and@source - The
safelist,corePluginsandseparatorconfig options. To safelist utilities in v4, use@source inline(...) - JavaScript-based plugin registration via
plugins: [require('...')]. Plugins use CSS imports or the@plugindirective
Step-by-Step Migration Guide
Here's the exact process to migrate to tailwind 4 from v3.
The upgrade tool handles most of it automatically, but understanding each step helps when something breaks.
Step 1: Run the Upgrade Tool
The fastest path is the automated upgrade.
It needs Node.js 20 or higher, and you want a clean git branch before you run it:
npx @tailwindcss/upgrade@latest
This tool scans your project and automatically:
- Converts
@tailwinddirectives to@import "tailwindcss" - Migrates
tailwind.config.jsto@themein your CSS - Updates PostCSS configuration
- Renames deprecated utilities in your templates
- Adjusts import paths
For most projects the upgrade tool does the bulk of the work.
Run it first, then fix what's left by hand.
Step 2: Update Dependencies
# Remove old packages
npm uninstall tailwindcss postcss-import
# Install Tailwind 4
npm install tailwindcss@latest
# Install the integration for your build tool
npm install -D @tailwindcss/postcss # For PostCSS users
# OR
npm install -D @tailwindcss/vite # For Vite users
# OR
npm install -D @tailwindcss/cli # For CLI-only builds
Step 3: Update Your CSS Entry Point
Replace the old directives with the new import:
/* Before (v3) */
@tailwind base;
@tailwind components;
@tailwind utilities;
/* After (v4) */
@import "tailwindcss";
Add your theme configuration below the import:
@import "tailwindcss";
@theme {
--color-primary: #3B82F6;
--color-secondary: #10B981;
--font-sans: "Inter", sans-serif;
}
Step 4: Update Build Configuration
For PostCSS users, update postcss.config.js:
// Before (v3)
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}
// After (v4)
module.exports = {
plugins: {
'@tailwindcss/postcss': {},
},
}
Note: autoprefixer is no longer needed.
Tailwind css 4 handles vendor prefixing automatically.
For Vite users, update vite.config.js:
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [tailwindcss()],
})
No PostCSS configuration is needed when using the Vite plugin.
Step 5: Migrate Configuration
Convert your tailwind.config.js theme values to @theme:
@import "tailwindcss";
@theme {
/* Colors */
--color-brand: #6366F1;
--color-brand-light: #818CF8;
--color-brand-dark: #4F46E5;
/* Typography */
--font-heading: "Cal Sans", sans-serif;
--font-body: "Inter", sans-serif;
/* Custom spacing */
--spacing-128: 32rem;
--spacing-144: 36rem;
/* Border radius */
--radius-lg: 0.75rem;
--radius-xl: 1rem;
/* Breakpoints */
--breakpoint-3xl: 1920px;
}
JavaScript config files still work, but v4 no longer detects them automatically.
If you need one (for complex plugins or dynamic values), load it explicitly with @config:
@import "tailwindcss";
@config "../tailwind.config.js";
This backward compatibility bridge lets you migrate incrementally.
Step 6: Delete Old Configuration Files
Once everything works with CSS-first configuration:
rm tailwind.config.js
Also remove any postcss-import references and old Tailwind-specific PostCSS plugins from your project.
Step 7: Test and Fix
Run your build and check for:
- Missing styles (classes that got purged incorrectly)
- Color differences (default palette values changed)
- Dark mode behavior (verify your strategy is applied correctly)
- Plugin output (ensure third-party plugins render correctly)
You're done when the build passes and the UI matches what it looked like before.
For projects using Tailwind templates, verify that template-specific customizations survive the migration.
Framework-Specific Setup
Next.js Setup
For Next.js projects with Tailwind, the setup depends on whether you use the Pages Router or App Router.
App Router (recommended):
Install the PostCSS plugin:
npm install -D @tailwindcss/postcss
Update postcss.config.mjs:
const config = {
plugins: {
"@tailwindcss/postcss": {},
},
};
export default config;
Update your global CSS file (app/globals.css):
@import "tailwindcss";
@theme {
--color-primary: #3B82F6;
--font-sans: "Inter", sans-serif;
}
Import it in app/layout.tsx:
import './globals.css'
No tailwind.config.js or tailwind.config.ts needed.
Delete them after migration.
Vite + React Setup
npm install -D @tailwindcss/vite
Update vite.config.ts:
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite'
export default defineConfig({
plugins: [react(), tailwindcss()],
})
Update src/index.css:
@import "tailwindcss";
Import in your root component.
No PostCSS configuration needed.
CLI-Only Setup
For projects without a bundler:
npm install -D @tailwindcss/cli
Build your CSS:
npx @tailwindcss/cli -i src/input.css -o dist/output.css --watch
The input CSS file uses the same @import "tailwindcss" syntax.
Plugin Compatibility
After browser support, plugin compatibility is what teams worry about most.
Here's where the major ones stand.
Fully Compatible
| Plugin | Status | Notes |
|---|---|---|
| Headless UI | Works | No changes needed. Headless components use className props |
| Radix UI | Works | Headless library, applies Tailwind classes normally |
| shadcn/ui | Works | Updated for v4 CSS variables approach |
| Tailwind Typography | Works | Updated for v4 as @tailwindcss/typography |
| Tailwind Forms | Works | Updated for v4 as @tailwindcss/forms |
Requires Updates
| Plugin | Status | Notes |
|---|---|---|
| DaisyUI | Updated | v5 is the Tailwind 4 line. v4 of DaisyUI targets Tailwind 3 |
| Flowbite | Updated | Requires latest version for v4 support |
| Custom JS plugins | Migrate | Use @plugin directive or @config bridge |
Using Legacy Plugins
If a plugin has not been updated for tailwind v4, use the @config bridge:
@import "tailwindcss";
@config "../tailwind.config.js";
Then keep the plugin registration in your JavaScript config.
This runs the legacy plugin system alongside the new engine.
It's a bridge, not a permanent solution.
Plan to remove it once the plugin ships a v4-compatible version.
Before and After: Code Comparisons
Seeing the differences side by side makes the changes concrete.
Project Configuration
v3 project structure:
tailwind.config.js # JavaScript config
postcss.config.js # PostCSS with tailwindcss plugin
src/styles/globals.css # @tailwind directives
v4 project structure:
postcss.config.js # PostCSS with @tailwindcss/postcss (optional)
src/styles/globals.css # @import + @theme
Custom Colors
v3:
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
brand: {
50: '#eef2ff',
500: '#6366f1',
900: '#312e81',
}
}
}
}
}
v4:
@theme {
--color-brand-50: #eef2ff;
--color-brand-500: #6366f1;
--color-brand-900: #312e81;
}
Usage remains identical in both versions: bg-brand-500, text-brand-50, etc.
Custom Components
v3:
@layer components {
.btn-primary {
@apply px-6 py-3 bg-blue-500 text-white rounded-lg
hover:bg-blue-600 transition-colors;
}
}
v4:
@layer components {
.btn-primary {
@apply px-6 py-3 bg-blue-500 text-white rounded-lg
hover:bg-blue-600 transition-colors;
}
}
@apply still works inside @layer blocks, and v4's native cascade layers give you guaranteed specificity ordering.
But for custom utilities, v4 added a better directive.
Instead of @layer utilities, use @utility:
@utility content-auto {
content-visibility: auto;
}
Utilities defined this way land in the utilities layer automatically and work with variants like hover: and lg:.
That's the recommended path in v4 for anything you'd previously have registered as a custom utility.
Dark Mode
v3 (with config):
// tailwind.config.js
module.exports = {
darkMode: 'class',
}
v4 (with CSS):
@import "tailwindcss";
@custom-variant dark (&:where(.dark, .dark *));
Usage in HTML remains the same: dark:bg-gray-900, dark:text-white.
Common Migration Errors and Fixes
These are the errors people hit most often when upgrading.
"It looks like you're trying to use tailwindcss directly as a PostCSS plugin"
Cause: Your postcss.config.js still references tailwindcss instead of @tailwindcss/postcss.
Fix:
// Replace this:
plugins: { tailwindcss: {} }
// With this:
plugins: { '@tailwindcss/postcss': {} }
Missing default styles or broken dark mode
Cause: Incomplete config migration. Default values changed between v3 and v4.
Fix: Explicitly define any v3 defaults you relied on in your @theme block. For dark mode, add the @custom-variant dark directive if you toggle dark mode with a class.
Utility classes being purged unexpectedly
Cause: Automatic content detection is missing some files. This can happen with files outside the project root or dynamically generated class names.
Fix: Add explicit source paths:
@source "../packages/shared-ui/**/*.tsx";
@source "./data/**/*.json";
Plugin errors after upgrade
Cause: JavaScript plugins reference v3 API methods that no longer exist.
Fix: Add the @config bridge temporarily:
@import "tailwindcss";
@config "../tailwind.config.js";
Then update or replace the plugin when a v4-compatible version ships.
Border colors changed
Cause: Default border color changed from gray-200 to currentColor in v4.
Fix: Add explicit border colors where you previously relied on the default:
<!-- Add explicit color where borders look wrong -->
<div class="border border-gray-200">...</div>
Or set the default globally:
@layer base {
*,
::after,
::before {
border-color: var(--color-gray-200);
}
}
Should You Upgrade Now?
So should you? It depends on your project.
Upgrade now if:
- You are starting a new project. There is zero reason to start with v3 in 2026. Version 4 is the default
- Build performance matters. If your dev server or CI pipeline is slow because of Tailwind processing, the 2-5x speedup is worth the migration effort
- You want CSS-first configuration. The
@themeapproach is simpler, more portable, and eliminates the JavaScript config dependency - You need container queries or 3D transforms. These features are only available in v4
- Your project uses standard plugins. If you rely on Headless UI, Radix, shadcn/ui, or official Tailwind plugins, compatibility is confirmed
Wait if:
- You still support older browsers. Safari below 16.4, Chrome below 111, or Firefox below 128 rules v4 out entirely. This is the blocker that matters, and it is the one people discover last
- Critical plugins have not been updated. If your project depends on niche plugins without v4 support, wait for those updates
- You are mid-sprint on a deadline. Migration is low-risk but not zero-risk. Do it during a dedicated maintenance window
- Your project is in maintenance mode. If you are not actively developing the project, the migration effort has no payback
For most teams the answer is yes, upgrade.
You get the performance immediately, the migration tool handles the heavy lifting, and the CSS-first workflow is genuinely nicer day to day.
Ship apps faster with AI
Generate production-ready Next.js apps from a prompt. Full code ownership, deploy anywhere, stunning design output.
Conclusion
Tailwind CSS 4 is a generational upgrade.
The Oxide engine makes builds measurably faster.
CSS-first configuration eliminates the JavaScript config file and makes your design tokens native CSS custom properties.
And automatic content detection removes an entire class of configuration bugs.
And new features like container queries and 3D transforms expand what you can build with utility classes alone.
The migration path from v3 is well-supported.
Run npx @tailwindcss/upgrade on Node 20+, update your build configuration, convert your theme to @theme, and test.
How long it takes depends almost entirely on how much custom configuration and how many JavaScript plugins you have.
A stock project with the official plugins is quick.
A project with a hand-rolled plugin layer is not.
Start with the upgrade tool.
Fix any build errors.
Verify your UI visually.
Then delete your tailwind.config.js and get on with it.
That's a wrap.
Related Resources
Frequently Asked Questions
-
Yes. Tailwind 4 shipped stable in January 2025 with official Vite and PostCSS plugins, and the line has kept moving since: 4.3.3 is current as of July 2026. New projects should start on Tailwind 4 by default, and existing projects can migrate with the official upgrade tool. The one hard prerequisite is browser support. Tailwind 4 is designed for Safari 16.4+, Chrome 111+ and Firefox 128+, so if you still need to support older browsers, stay on the v3.4 LTS line instead.
-
Yes. Tailwind 4 works with Next.js including the App Router. You can integrate it through the @tailwindcss/postcss plugin or the @tailwindcss/vite plugin depending on your Next.js setup. Replace the old PostCSS configuration, switch your CSS entry point to use @import "tailwindcss", and migrate your tailwind.config.js to CSS-based @theme configuration. The Next.js community has reported no blockers with Tailwind 4 integration.
-
Tailwind 4 supports incremental migration. The official upgrade tool handles most conversions automatically and requires Node.js 20 or higher, so run it on a clean git branch. For large codebases a staged rollout works well: run the tool, fix build errors, then gradually convert custom configuration and plugins to the CSS-first approach. The tailwind.config.js file still works through the @config directive during the transition, though v4 will not load it unless you point at it explicitly.
-
Tailwind 4 replaces tailwind.config.js with CSS-first configuration using the @theme directive. Instead of defining colors, fonts and spacing in JavaScript, you define them as CSS custom properties in your stylesheet, using the documented namespaces: --color-* for colors, --font-* for font families, --spacing-* for spacing, --breakpoint-* for breakpoints. Note that it is --font-*, not --font-family-*, which is a common mistake that silently produces no utility. JavaScript config files still work through the @config directive, but v4 no longer picks them up automatically, so you have to load them explicitly.
-
Yes, and the official figures are specific. Benchmarking their own Catalyst template, the Tailwind team measured a full build dropping from 378ms in v3.4 to 100ms in v4, an incremental rebuild that adds new CSS going from 44ms to 5ms, and an incremental rebuild that adds no new CSS going from 35ms to 192 microseconds. That last one is the number you feel during development, because most edits reuse classes that already exist. It is why hot module replacement in v4 feels instant.
-
Most popular plugins have been updated. Headless UI and Radix work without changes because they are headless component libraries that just take className props. The official typography and forms plugins have v4 releases. DaisyUI moved to v5 for its Tailwind 4 line, so DaisyUI v4 targets Tailwind 3 and DaisyUI v5 targets Tailwind 4. Plugins that leaned on the JavaScript config API may need the @config directive as a temporary bridge.
-
The one that stops migrations dead is browser support: v4 targets Safari 16.4+, Chrome 111+ and Firefox 128+, and no tool can work around that. After that, the big three are the shift from JavaScript config to CSS-first @theme configuration, the replacement of @tailwind directives with @import "tailwindcss", and the removal of the tailwindcss PostCSS plugin in favour of @tailwindcss/postcss. Visual changes to watch for: the default border colour became currentColor instead of gray-200, and the ring utility went from 3px blue-500 to 1px currentColor. The safelist, corePlugins and separator config options are gone, replaced by @source inline() for safelisting. The upgrade tool handles most of the mechanical work.
-
Upgrade for new projects without question. For existing projects, upgrade if you want faster builds, CSS-first configuration and features like container queries and 3D transforms. Wait if you still need to support Safari below 16.4, Chrome below 111 or Firefox below 128, because that rules v4 out entirely and is the constraint people discover last. Also wait if a critical plugin has no v4 release yet. Otherwise the path is well documented and the upgrade tool automates most of the mechanical changes.
Next.js SaaS Starter Kit
Pre-built auth, billing, and dashboard. Launch your SaaS in days, not weeks.
Join 50k+ subscribers
Web dev, SaaS, growth & marketing. Weekly.
Keep Learning
More articles you might find interesting.