Migrating to Tailwind CSS v4
Tailwind CSS v4 (released January 2025) is a ground-up rewrite. The new Oxide engine (Rust plus Lightning CSS) builds dramatically faster, configuration moved from JavaScript to CSS (@theme), content detection became automatic, and the framework embraces modern CSS: cascade layers, @property, color-mix(), container queries, and OKLCH colors. For most projects, migrating is worthwhile: faster builds, less configuration, and new features.
It also has breaking changes: renamed utilities, different defaults for borders and rings, removed deprecated classes, new installation packages, and a higher browser baseline. The official upgrade tool automates most of the work; the rest is reviewing visual differences and moving custom configuration.
TL;DR
- Run
npx @tailwindcss/upgradeon a clean branch. It updates dependencies, config, templates, and CSS. - Replace
@tailwind base/components/utilitieswith@import "tailwindcss";. - Use
@tailwindcss/vite(recommended) or@tailwindcss/postcss; autoprefixer and postcss-import are no longer needed. - Move
tailwind.config.jscustomizations into@theme(or keep them temporarily via@config). - Watch for renamed utilities (
shadow-sm→shadow-xs,rounded→rounded-sm,outline-none→outline-hidden…) and default changes (border color, ring width). - v4 targets modern browsers (Safari 16.4+, Chrome 111+, Firefox 128+). Stay on v3.4 if you must support older ones.
Quick Example
Before (v3):
After (v4):
Core Concepts
What Changed in v4
- Performance: full builds several times faster, and incremental builds often measured in microseconds.
- CSS-first configuration:
@theme,@utility,@custom-variant,@plugin,@source. See theme configuration. - Automatic content detection: no
contentarray;.gitignored files are skipped. - Theme values as CSS variables available at runtime.
- Modern CSS: native cascade layers,
@property-registered variables,color-mix()for opacity modifiers, logical properties. - New features: container queries built in, 3D transforms, expanded gradients (
bg-linear-*, conic and radial),@starting-style(starting:),not-*andin-*variants, and dynamic utility values (grid-cols-15,w-17) without configuration.
Installation Changes
Notable Utility Renames
The upgrade tool rewrites most of these in templates automatically.
Default Style Changes
- Border color defaults to
currentColorinstead ofgray-200, so a barebordermay look darker. Add explicit colors, or restore the old default in base styles. - Ring defaults to 1px
currentColorinstead of 3px blue. - Placeholder text uses the current text color at 50% opacity.
- Buttons use
cursor: default(the browser default). hover:only applies on devices that support hover (@media (hover: hover)).- Variant stacking order is now left to right, matching CSS nesting intuition.
space-*anddivide-*use a different selector for performance, which can change behavior with inline elements. Prefergapin flex and grid layouts.
JavaScript Config Compatibility
@config "./tailwind.config.js"; loads a v3-style config, which is useful for incremental migration or complex plugin setups. Some options aren't supported (corePlugins, safelist, separator). resolveConfig is gone, since theme values are CSS variables now (read them with getComputedStyle).
Browser Support
v4 relies on modern CSS features (cascade layers, @property, color-mix), requiring Safari 16.4+, Chrome 111+, and Firefox 128+. Projects that must support older browsers should stay on v3.4, which remains maintained.
Migration Plan
- Check browser requirements against your analytics and support policy.
- Upgrade on a branch with a clean working tree, and run the upgrade tool (Node 20+).
- Switch the build integration to
@tailwindcss/viteor@tailwindcss/postcss, and remove autoprefixer and postcss-import. - Move configuration into
@theme, custom utilities into@utility, and dark mode into@custom-variant, or keep@configtemporarily. - Update third-party tooling: Prettier plugin, IntelliSense, tailwind-merge (a v4-compatible version), component libraries, and
@applyusage in CSS modules or Vue and Svelte<style>blocks (add@reference). - Review visually: run visual regression tests or walk through key pages in light and dark themes, paying attention to borders, rings, shadows, and placeholders.
- Clean up leftover v3 patterns (opacity utilities,
theme()calls, and deprecated names) after things work.
Best Practices
Rely on Visual Regression Tests
Many changes are subtle (1px rings, border colors, shadow sizes). Screenshot tests with Playwright or Storybook catch what code review misses.
Migrate Configuration Gradually
Using @config first gets you v4's engine immediately, and you can convert theme values to @theme incrementally, which reduces risk on large codebases.
Adopt CSS Variables for Theming
v4 exposes the theme as CSS variables, so it's a good moment to move to semantic tokens and simplify dark mode. See Tailwind dark mode.
Update Component Libraries in Lockstep
shadcn/ui, Headless UI, and Tailwind plugin packages have v4-compatible releases. Upgrade them together to avoid mixed assumptions about defaults.
Common Mistakes
Keeping Old PostCSS Setup
Leaving tailwindcss as a PostCSS plugin alongside @tailwindcss/postcss, or keeping @tailwind directives, leads to confusing build errors or missing styles. Remove the v3 wiring entirely.
Ignoring Border and Ring Defaults
Components that relied on the default gray border or the 3px blue focus ring look different after upgrading. Search for bare border and ring classes, and make colors and widths explicit.
Upgrading Without Checking Browser Support
Enterprise users on older Safari versions may see broken layouts. Verify your browser matrix before shipping v4.
FAQ
Is Tailwind v4 backward compatible with v3?
Mostly in spirit, but not entirely. Utilities work similarly, but some were renamed, defaults changed (border color, ring width), deprecated utilities were removed, and configuration moved to CSS. The official upgrade tool handles the majority of changes automatically.
Do I have to rewrite tailwind.config.js?
Not immediately. @config loads existing JavaScript configs so you can upgrade the engine first. Over time, moving to @theme gives you runtime CSS variables and simpler configuration.
Does Tailwind v4 still need PostCSS?
Not necessarily. Vite projects should use @tailwindcss/vite. Other setups can use @tailwindcss/postcss (which bundles import handling and vendor prefixing) or the standalone CLI. Autoprefixer and postcss-import are no longer needed.
Which browsers does Tailwind v4 support?
Modern evergreen browsers: Safari 16.4+, Chrome and Edge 111+, and Firefox 128+. For older browser support, stay on Tailwind v3.4.
Related Topics
- Tailwind — The framework overview
- Tailwind Theme Configuration — The new @theme system
- Tailwind Component Patterns — tailwind-merge and tooling updates
- Vite — The recommended build integration
- CSS Cascade & Specificity — Cascade layers used by v4
- Playwright — Visual regression testing during migration