← All articles
FRONTEND Tailwind CSS v4: What Changed and How to Migrate 2026-03-04 · 4 min read · tailwind · css · tailwind v4

Tailwind CSS v4: What Changed and How to Migrate

Frontend 2026-03-04 · 4 min read tailwind css tailwind v4 frontend styling vite react migration

Tailwind CSS v4 is not an incremental update. It's a ground-up rewrite with a new CSS engine (Lightning CSS, written in Rust), a new configuration model (CSS-first instead of JS config file), and significantly faster builds. It also drops several v3 APIs that accumulated technical debt.

If you're starting a new project, v4 is the right choice. If you're on v3, this guide explains what changed and how to migrate.

What's New in v4

1. Lightning CSS Engine

v4 uses Lightning CSS as its parser and transformer instead of PostCSS. Lightning CSS is written in Rust and is substantially faster. Build times drop from seconds to milliseconds for most projects, with the performance gap widening on large codebases.

Benchmark: a large Next.js project that took 3.2s with v3 PostCSS typically takes 90ms with v4.

2. No Configuration File Required

v3 required a tailwind.config.js (or .ts) file for any customization. v4 moves configuration into CSS itself using @theme:

/* app.css */
@import "tailwindcss";

@theme {
  --color-primary: #3b82f6;
  --color-primary-dark: #1d4ed8;
  --font-display: "Inter", sans-serif;
  --spacing-18: 4.5rem;
}

You can still use a JavaScript config file for advanced tooling integrations, but it's no longer required for typical customization.

3. CSS-First Theme Variables

In v4, your theme values are CSS custom properties. This means they're available everywhere — not just in Tailwind classes:

.my-component {
  background: var(--color-primary);
  padding: var(--spacing-4);
}

And in JavaScript:

const primaryColor = getComputedStyle(document.documentElement)
  .getPropertyValue('--color-primary').trim();

This makes the theme genuinely shared between Tailwind classes and custom CSS, eliminating the previous pattern of importing values from the config file.

4. New Vite Plugin

The recommended setup for v4 with Vite uses a first-party plugin instead of PostCSS:

npm install tailwindcss @tailwindcss/vite
// vite.config.js
import { defineConfig } from 'vite'
import tailwindcss from '@tailwindcss/vite'

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

PostCSS is still supported but the Vite plugin is faster and simpler for Vite-based projects.

5. Simplified Directives

v3 had three directives: @tailwind base, @tailwind components, @tailwind utilities. v4 replaces all three with a single import:

/* v3 */
@tailwind base;
@tailwind components;
@tailwind utilities;

/* v4 */
@import "tailwindcss";

6. Container Queries Built In

v4 includes native container query support without a plugin:

<div class="@container">
  <div class="@sm:flex @lg:grid-cols-3">
    <!-- Responds to container width, not viewport -->
  </div>
</div>

In v3, this required the @tailwindcss/container-queries plugin.

7. New Variant Syntax

Some variant syntax changed in v4:

<!-- v3 -->
<div class="group-hover:opacity-50">

<!-- v4 (still works, plus new arbitrary variants) -->
<div class="group-hover:opacity-50 group-[.active]:opacity-100">

v4 also adds not-* variants:

<div class="not-hover:opacity-75 not-first:mt-4">

Installation for New Projects

With Vite (React, Vue, etc.):

npm install tailwindcss @tailwindcss/vite
// vite.config.js
import tailwindcss from '@tailwindcss/vite'

export default {
  plugins: [tailwindcss()]
}
/* src/index.css */
@import "tailwindcss";

With Next.js:

npm install tailwindcss @tailwindcss/postcss postcss
// postcss.config.mjs
export default {
  plugins: {
    '@tailwindcss/postcss': {}
  }
}

CLI (no bundler):

npm install tailwindcss @tailwindcss/cli
npx @tailwindcss/cli -i src/input.css -o dist/output.css --watch

Migrating from v3

The Tailwind team provides an automated migration codemod:

npx @tailwindcss/upgrade@next

This handles the most common changes automatically. What it does:

Manual Changes Required

Some things the codemod doesn't handle:

bg-opacity-*, text-opacity-*, border-opacity-* utilities removed:

<!-- v3 -->
<div class="bg-blue-500 bg-opacity-50">

<!-- v4 -->
<div class="bg-blue-500/50">

flex-shrink and flex-grow renamed:

<!-- v3 -->
<div class="flex-shrink-0 flex-grow">

<!-- v4 -->
<div class="shrink-0 grow">

overflow-ellipsis renamed:

<!-- v3: -->
<div class="overflow-ellipsis">

<!-- v4: -->
<div class="text-ellipsis">

JIT is now the only mode: v3's non-JIT mode (full CSS generation) is gone. v4 always generates only the classes you use.

theme() function syntax changed: In CSS, use CSS variables instead of theme():

/* v3 */
.foo { color: theme('colors.blue.500'); }

/* v4 */
.foo { color: var(--color-blue-500); }

Config File Migration

If you have a complex tailwind.config.js, the codemod converts it, but review the output. Complex configurations with plugins may need manual adjustment.

Custom colors:

// tailwind.config.js (v3)
module.exports = {
  theme: {
    extend: {
      colors: {
        brand: '#ff5500',
      }
    }
  }
}

Becomes:

/* app.css (v4) */
@import "tailwindcss";
@theme {
  --color-brand: #ff5500;
}

Custom breakpoints:

@theme {
  --breakpoint-xs: 475px;
  --breakpoint-3xl: 1920px;
}

Custom fonts:

@theme {
  --font-display: "Inter Variable", sans-serif;
}

v3 Features Removed in v4

Removed Replacement
bg-opacity-* utilities Opacity modifier syntax (bg-blue-500/50)
text-opacity-* utilities Opacity modifier syntax (text-blue-500/75)
flex-shrink shrink
flex-grow grow
decoration-slice box-decoration-slice
decoration-clone box-decoration-clone
overflow-ellipsis text-ellipsis
transform (standalone class) Implicit — transform utilities auto-apply
filter (standalone class) Implicit — filter utilities auto-apply
ring-offset-* Changed implementation

Run the codemod and check its output for these replacements.

Dark Mode in v4

Dark mode configuration moved to CSS:

/* v4 */
@import "tailwindcss";

@variant dark (&:where([data-theme=dark] *));
/* or: */
@variant dark (@media (prefers-color-scheme: dark));

The dark: variant works the same in HTML:

<div class="bg-white dark:bg-gray-900">

Should You Upgrade Now?

Upgrade if: Starting a new project, have good test coverage, or the codebase is small.

Wait if: Large production app with many custom plugins, complex configuration, or limited time for testing. v3 continues to receive security patches.

The migration path is well-defined for most projects, but edge cases with third-party plugins (forms, typography, aspect-ratio, etc.) may require plugin upgrades that aren't available yet. Check that the plugins you depend on have v4-compatible versions.

The official upgrade guide documents all breaking changes in detail.