--- title: "Migrating to Tailwind CSS v4" date: 2026-05-13T08:00:00+08:00 draft: false description: "CSS-first configuration, the new @theme directive, container queries, and what actually changed from v3. A practical migration log." tags: - CSS - Tailwind - Frontend --- 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: ```css @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: ```html
...
``` ### 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.