Development8 min read

Tailwind CSS v4 2026: Migration Best Practices

Tailwind CSS v4 replaces config files with CSS-native theme variables and drops 40% of legacy classes. Migration guide with breaking changes and automated codemods.

Digital Applied Team
February 9, 2026
8 min read
5x

Faster Build Speed vs v3

40%

Fewer Legacy Class Aliases

~100ms

Full Rebuild Time in v4

90%

Changes Automated by Codemod

Key Takeaways

CSS-native configuration replaces tailwind.config.js entirely: Tailwind CSS v4 moves all theme configuration into your CSS file using @theme directives. JavaScript config files are no longer required, reducing toolchain complexity and enabling runtime theme switching without rebuilds.
The automated upgrade tool handles 90% of class renames: Running npx @tailwindcss/upgrade converts legacy class aliases like bg-gradient-to-r, flex-shrink-0, and flex-grow to their v4 canonical equivalents. Manual review is still required for custom plugins and complex configurations.
The new engine is 5x faster with a unified toolchain: Tailwind v4 ships its own bundler integration, eliminating the need for separate PostCSS plugins. Full rebuilds that took 3.5 seconds in v3 complete in under 100ms in v4, with incremental builds measuring in single-digit milliseconds.
bg-linear-to-* replaces bg-gradient-to-* across all gradient utilities: All gradient direction utilities now use the CSS-native linear-gradient naming convention. This is the most common breaking change affecting virtually every project that uses Tailwind gradient backgrounds.
Design systems must migrate from JS tokens to CSS custom properties: Multi-theme design systems previously relying on multiple tailwind.config.js files can now implement runtime theme switching using CSS variable overrides at the :root or [data-theme] selector level — no rebuild needed.

Tailwind CSS v4 is the most significant release in the framework's history. After years of incremental improvements to the v3 architecture, the Tailwind Labs team rewrote the engine from the ground up — replacing the Node.js build pipeline with a high-performance Rust-based engine, eliminating the JavaScript configuration file in favour of CSS-native @theme directives, and canonicalising utility class names to match CSS specifications. The result is a framework that is fundamentally faster, simpler to configure, and better aligned with where the web platform is heading.

The trade-off is a migration path that requires attention. Legacy class aliases accumulated over years of Tailwind history — names like bg-gradient-to-r, flex-shrink-0, and overflow-ellipsis — are removed. Configuration that lived in tailwind.config.js must move into CSS. This guide walks through every breaking change, the automated migration tooling, and the new features that make the upgrade worthwhile.

What Changed in Tailwind CSS v4

Tailwind CSS v4 introduces three architectural changes that affect every project upgrading from v3: a new engine built on a high-performance Rust core, a CSS-native configuration system replacing the JavaScript config file, and a class name canonicalisation pass that removes legacy aliases. Understanding what changed at the architecture level clarifies why the migration steps are what they are.

New Engine

Rust-based core with a unified bundler integration. Eliminates PostCSS plugin chain. Full rebuilds in under 100ms, incremental builds in single-digit milliseconds.

CSS-Native Config

Theme configuration moves from tailwind.config.js into @theme directives in CSS. Design tokens become CSS custom properties available natively in the browser.

Class Canonicalisation

Legacy class aliases removed in favour of CSS-spec names. Gradient utilities, flex shorthand, and overflow utilities are the most commonly renamed classes across the ecosystem.

The Unified Toolchain Model

In Tailwind v3, the build pipeline required postcss, autoprefixer, and tailwindcss as separate packages wired together in a postcss.config.js. Tailwind v4 ships native integrations for Vite (@tailwindcss/vite) and PostCSS (@tailwindcss/postcss) that handle CSS processing, vendor prefixes, and Tailwind compilation in a single package. The PostCSS config simplifies to a single plugin entry.

postcss.config.js — v3 vs v4

// v3 — three separate packages
module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
};

// v4 — single package handles everything
module.exports = {
  plugins: {
    "@tailwindcss/postcss": {},
  },
};

For projects using Vite, the PostCSS config is no longer needed at all. Import the Vite plugin in vite.config.ts and add a single @import "tailwindcss" line in your global CSS file — that is the entire setup. Next.js projects (which use PostCSS) switch to the @tailwindcss/postcss package for a similarly streamlined configuration. For a deeper look at how this toolchain fits into modern Next.js architecture, see our Next.js 16 performance and server components guide.

Breaking Changes Checklist

Tailwind v4 removes all class aliases that did not match their underlying CSS property names. The table below covers every renamed utility you are likely to encounter in a real codebase. Classes not listed here are unchanged and work identically in v4.

Categoryv3 Legacy Class (Remove)v4 Canonical Class (Use)
Gradientsbg-gradient-to-tbg-linear-to-t
Gradientsbg-gradient-to-trbg-linear-to-tr
Gradientsbg-gradient-to-rbg-linear-to-r
Gradientsbg-gradient-to-brbg-linear-to-br
Gradientsbg-gradient-to-bbg-linear-to-b
Gradientsbg-gradient-to-blbg-linear-to-bl
Gradientsbg-gradient-to-lbg-linear-to-l
Gradientsbg-gradient-to-tlbg-linear-to-tl
Flexboxflex-shrinkshrink
Flexboxflex-shrink-0shrink-0
Flexboxflex-growgrow
Flexboxflex-grow-0grow-0
Text Overflowoverflow-ellipsistext-ellipsis
Text Overflowoverflow-cliptext-clip
Background Sizebg-[size:200%]bg-size-[200%]
Mask Image[mask-image:...]mask-[...]
Aspect Ratioaspect-[16/9]aspect-video
Shadowdrop-shadow-smdrop-shadow-xs
Shadowshadow-smshadow-xs
Ringring (3px default)ring-3
Blurblur-sm (4px)blur-xs

Automated Migration with Codemods

The Tailwind team provides an official upgrade tool that automates the class renames, config file migration, and package updates. For most projects, running the codemod is the correct starting point — manual class hunting is error-prone and time-consuming when the tool handles it reliably.

Running the Upgrade Tool

Terminal — run the official upgrade codemod

# Run from your project root
npx @tailwindcss/upgrade

# For specific directories
npx @tailwindcss/upgrade --config ./tailwind.config.js

# Preview changes without writing files (dry run)
npx @tailwindcss/upgrade --dry-run

The upgrade tool performs the following operations automatically:

Package updates

Uninstalls tailwindcss v3, installs tailwindcss v4 and the appropriate integration package (@tailwindcss/postcss or @tailwindcss/vite).

Config file migration

Reads tailwind.config.js and converts theme extensions, custom colours, spacing, and font scales into @theme directives in your global CSS file.

Class renames across all files

Scans HTML, JSX, TSX, Vue, Svelte, and CSS files for legacy class aliases and replaces them with v4 canonical names.

PostCSS config update

Updates postcss.config.js to use @tailwindcss/postcss and removes the autoprefixer entry (now built into the package).

CSS import update

Converts @tailwind base; @tailwind components; @tailwind utilities; directives to a single @import "tailwindcss" statement.

What the Codemod Cannot Handle

The upgrade tool handles class renames and straightforward configuration migration, but several scenarios require manual intervention:

Dynamically constructed class names

If your codebase builds class names programmatically (e.g., 'bg-gradient-to-' + direction), the codemod cannot detect these. Search for string patterns containing gradient-to-, flex-shrink, and flex-grow across your codebase and update any dynamic class construction manually.

Custom plugins using the v3 plugin API

Plugins using plugin(), addUtilities(), matchUtilities(), or the theme() callback require manual refactoring. Simple addUtilities plugins can be replaced with @utility definitions in CSS. Complex plugins need individual evaluation.

Third-party component libraries

Component libraries like shadcn/ui, daisyUI, and Headless UI have their own v4 migration guides. Check each library's changelog and update to v4-compatible versions before or alongside the Tailwind upgrade. Running the codemod on node_modules is not effective — library migrations must come from updated package versions.

CSS-Native Theme Configuration

The most architecturally significant change in Tailwind v4 is the elimination of the JavaScript config file for theme configuration. All design tokens — colours, spacing, typography, border radius, shadows — now live in a @theme block in your global CSS file. This is not merely a syntax change: it fundamentally changes how theme tokens are consumed in the browser.

From tailwind.config.js to @theme

v3 — tailwind.config.js theme extension

// tailwind.config.js (v3)
module.exports = {
  theme: {
    extend: {
      colors: {
        brand: {
          50:  "#eff6ff",
          500: "#3b82f6",
          900: "#1e3a8a",
        },
      },
      fontFamily: {
        sans: ["Geist", "system-ui", "sans-serif"],
      },
      borderRadius: {
        "4xl": "2rem",
      },
    },
  },
};

v4 — globals.css @theme directive

/* globals.css (v4) */
@import "tailwindcss";

@theme {
  --color-brand-50:  #eff6ff;
  --color-brand-500: #3b82f6;
  --color-brand-900: #1e3a8a;

  --font-sans: "Geist", system-ui, sans-serif;

  --radius-4xl: 2rem;
}

The key insight is that @theme variables are real CSS custom properties accessible throughout your stylesheet with var(--color-brand-500). You get the Tailwind utility classes (text-brand-500, bg-brand-50) and access to the raw CSS custom property in the same token — no duplication needed.

Runtime Theme Switching

Because theme tokens are CSS custom properties, runtime theme switching no longer requires a rebuild. Override the @theme variables at a selector level and every Tailwind utility using those tokens updates automatically:

globals.css — multi-theme with CSS variable overrides

@import "tailwindcss";

@theme {
  /* Default (light) theme */
  --color-surface: #ffffff;
  --color-surface-raised: #f4f4f5;
  --color-text-primary: #18181b;
  --color-accent: #3b82f6;
}

/* Dark theme — override tokens at selector level */
[data-theme="dark"] {
  --color-surface: #09090b;
  --color-surface-raised: #18181b;
  --color-text-primary: #fafafa;
  --color-accent: #60a5fa;
}

/* High contrast theme */
[data-theme="high-contrast"] {
  --color-surface: #000000;
  --color-text-primary: #ffffff;
  --color-accent: #ffff00;
}

Switching themes is a single attribute change on the <html> element: document.documentElement.dataset.theme = 'dark'. This replaces multi-config setups that previously required separate Tailwind builds or complex CSS-in-JS theming solutions. For projects building headless storefronts with complex theming requirements, see our headless CMS comparison for 2026.

New Utilities and Features

Beyond the migration work, Tailwind v4 ships a substantial set of new utilities that were not available in v3. These additions reduce reliance on arbitrary values and cover CSS features that have reached broad browser support in 2024-2026.

Container Queries
@container-based responsive design

First-class container query support without the @tailwindcss/container-queries plugin. Use @container on a parent and @sm:, @md:, @lg: variants on children.

<div class="@container">
  <p class="@sm:text-lg @lg:text-2xl">
    Responsive to its container
  </p>
</div>
Wide Gamut Color Support
oklch, lab, and display-p3 colors

Tailwind v4 ships its default color palette in OKLCH, enabling wide-gamut colors on supported displays. All colour utilities are defined using oklch() by default, with sRGB fallbacks generated automatically for older browsers.

@theme {
  /* Wide-gamut custom color */
  --color-brand: oklch(0.6 0.2 250);
}
@utility CSS Directive
Custom utilities without JavaScript plugins

Define custom utilities directly in CSS using the @utility directive. Tailwind handles variant generation (hover:, focus:, dark:, responsive) automatically for all custom utilities.

@utility tab-4 {
  tab-size: 4;
}

/* Usage: class="tab-4 hover:tab-4" */
3D Transform Utilities
perspective, rotate-x/y, translate-z

Full 3D transform support with perspective-*, rotate-x-*, rotate-y-*, and translate-z-* utilities. No more arbitrary values or custom CSS for card flip animations and perspective effects.

<div class="perspective-800 rotate-y-12
            hover:rotate-y-0 transition-transform">
  Card with 3D effect
</div>

Additional new utilities in v4 include field-sizing-content for auto-resizing textareas, text-wrap-balance and text-wrap-pretty for typographic wrapping control, inset-shadow-* for inner shadow utilities, and not-* variants for CSS :not() selector support.

Performance Improvements

The performance story for Tailwind v4 is the most compelling reason to upgrade for teams working on large codebases. The new engine, built on a Rust core called Lightning CSS, replaces the Node.js-based PostCSS pipeline that had been the bottleneck for large projects running full Tailwind rebuilds.

OperationTailwind v3Tailwind v4Improvement
Full rebuild (large project)~3,500ms~100ms35x faster
Incremental rebuild~350ms~5ms70x faster
Dev server startup~800ms~50ms16x faster
CSS output sizeBaseline~15% smallerReduced bundle

The speed gains come from three sources. First, Lightning CSS processes CSS significantly faster than the Node.js PostCSS pipeline because Rust has dramatically lower per-operation overhead. Second, the v4 engine uses a smarter class scanning algorithm that only re-parses files that have changed since the last build rather than scanning the entire codebase on every hot-reload. Third, the unified toolchain eliminates the startup overhead of initialising multiple PostCSS plugins on each rebuild cycle.

Integration with Frameworks

Tailwind v4 ships first-party integrations for the most common JavaScript frameworks. The setup in each case is simpler than v3 because the unified toolchain handles what previously required manual PostCSS configuration.

Next.js (App Router)

Next.js uses PostCSS for CSS processing. Install @tailwindcss/postcss and update your postcss.config.mjs to use it as the sole plugin. In globals.css, replace the three @tailwind directives with a single import.

# Install
npm install tailwindcss @tailwindcss/postcss

# postcss.config.mjs
export default {
  plugins: {
    "@tailwindcss/postcss": {},
  },
};

# globals.css
@import "tailwindcss";

@theme {
  --font-sans: var(--font-geist-sans), system-ui, sans-serif;
  --font-mono: var(--font-geist-mono), monospace;
}

Vite

The Vite integration is the simplest setup. Install @tailwindcss/vite, add it to your Vite config plugins array, and delete the PostCSS config entirely.

# Install
npm install tailwindcss @tailwindcss/vite

// vite.config.ts
import tailwindcss from "@tailwindcss/vite";
import { defineConfig } from "vite";

export default defineConfig({
  plugins: [tailwindcss()],
});

/* main.css — single import replaces @tailwind directives */
@import "tailwindcss";

Remix / React Router v7

Remix and React Router v7 use Vite under the hood. The Vite plugin approach works identically. Add tailwindcss() to the plugins array in vite.config.ts before the Remix/React Router plugin, then update app/tailwind.css to use @import "tailwindcss".

Design System Migration

For teams maintaining a design system — a shared set of tokens, components, and theme definitions used across multiple projects — the Tailwind v4 migration requires a planned approach rather than a run-the-codemod-and-ship workflow. The good news is that the CSS-native token system in v4 is a significantly better foundation for design systems than the JavaScript config approach in v3.

Token Architecture in v4

In v3, design tokens lived in tailwind.config.js and were consumed exclusively through Tailwind utilities. Any component that needed a token value in a CSS property outside Tailwind's utility coverage had to duplicate the value or use a workaround. In v4, every @theme token is a CSS custom property, making it universally available across Tailwind utilities, CSS Modules, and inline styles alike.

design-tokens.css — shareable token layer

/* Shared across all apps in a monorepo */
@layer theme {
  @theme {
    /* Brand palette */
    --color-primary-50:  oklch(0.97 0.02 250);
    --color-primary-500: oklch(0.60 0.20 250);
    --color-primary-900: oklch(0.25 0.15 250);

    /* Semantic tokens */
    --color-surface:           var(--color-zinc-50);
    --color-surface-elevated:  #ffffff;
    --color-text-body:         var(--color-zinc-700);
    --color-text-heading:      var(--color-zinc-900);
    --color-border:            var(--color-zinc-200);

    /* Typography */
    --font-sans: "Inter", system-ui, sans-serif;
    --font-display: "Cal Sans", "Inter", sans-serif;

    /* Spacing scale additions */
    --spacing-18: 4.5rem;
    --spacing-22: 5.5rem;

    /* Border radius */
    --radius-pill: 9999px;
    --radius-card: 0.75rem;
  }
}

/* Dark theme overrides */
[data-theme="dark"] {
  --color-surface:          var(--color-zinc-950);
  --color-surface-elevated: var(--color-zinc-900);
  --color-text-body:        var(--color-zinc-300);
  --color-text-heading:     var(--color-zinc-50);
  --color-border:           var(--color-zinc-800);
}

Migration Checklist for Design Systems

Audit all tailwind.config.js files across packages and consolidate token definitions

Convert theme.extend.colors, theme.extend.spacing, and theme.extend.fontFamily to @theme variables

Update the shared CSS package to export @theme definitions rather than a JS config

Replace plugin() calls with @utility definitions in CSS where possible

Update consuming apps to @import the shared token CSS before @import 'tailwindcss'

Test dark mode and any theme variants by verifying CSS custom property overrides

Update component documentation to reference CSS variable names alongside utility class names

Verify Storybook integration by updating the Storybook Vite or Webpack config to use @tailwindcss/vite or @tailwindcss/postcss

Tailwind v4's CSS-native token system pairs exceptionally well with component-driven development workflows. Our web development services help teams establish scalable design systems and migrate existing codebases to modern toolchains without disrupting ongoing product development.

Ready to Upgrade Your Frontend Stack?

The Digital Applied web development team specialises in framework migrations, design system architecture, and modern CSS toolchain setup. From running the codemod to refactoring custom plugins and validating visual output, we handle the full Tailwind v4 migration lifecycle.

Explore Web Development Services
Frequently Asked Questions

Related Articles

Continue exploring with these related guides