跳至内容

Migrating to Tailwind CSS v4

2026-05-13

Tailwind v4 drops the JavaScript config file in favor of CSS-based configuration. The migration is mostly mechanical but there are gotchas with the @apply directive and custom variants.

CSS-First Configuration

The biggest change: tailwind.config.js is replaced by CSS. Your design tokens live in the @theme directive:

@import "tailwindcss";

@theme {
  --color-primary: #2563eb;
  --color-primary-dark: #1d4ed8;
  --font-sans: "Inter", sans-serif;
  --spacing-container: 1280px;
}

VSCode IntelliSense still works — the Tailwind CSS extension reads theme values from your stylesheet.

The Migration Path

  1. Install v4: npm install tailwindcss@next
  2. Run the automatic migration tool: npx @tailwindcss/upgrade
  3. Manually check @apply usages — the tool handles most cases, but deeply nested @apply with custom utilities sometimes breaks.
  4. Replace theme.extend in your old config with @theme blocks in CSS.

New Features Worth Using

Container Queries

No more media queries for component-level responsiveness. Tailwind v4 ships container query utilities:

<div class="@container">
  <div class="grid @lg:grid-cols-2">...</div>
</div>

Dynamic Utility Values

Arbitrary values are simpler: w-(--sidebar-width) references a CSS custom property. No more bracket syntax for common cases.

Native Cascade Layers

Tailwind v4 uses @layer to control specificity. Base, components, and utilities are layered in the correct order — @apply in component layer no longer risks specificity wars.

Gotchas

  • Custom variants defined in old JS config need to be re-registered via @variant in CSS.
  • The important config option now needs an explicit CSS strategy.
  • Some plugins haven’t updated yet — check compatibility before migrating production projects.

Overall, the migration took about two hours for a mid-sized project. The CSS-first approach feels more natural, and the build is noticeably faster thanks to the new Oxide engine.