1 min read
Migrating to Tailwind CSS v4: What Actually Changes
No more tailwind.config.ts, a CSS-first theme, and a handful of renamed utilities. Notes from migrating a production Next.js site to Tailwind v4.
Tailwind CSSCSS
Tailwind v4 moves configuration out of JavaScript and into your stylesheet. The first time you see it, the diff is jarring: the config file is gone, and the theme lives next to your tokens.
CSS-first configuration
@import "tailwindcss";
@custom-variant dark (&:is(.dark *));
@theme inline {
--color-background: hsl(var(--background));
--color-foreground: hsl(var(--foreground));
--font-sans: var(--font-geist-sans), system-ui, sans-serif;
}Design tokens become first-class CSS variables under the @theme block, and every utility is generated from them. If you were already running a CSS-variable design system (the shadcn/ui pattern), the migration is mostly mechanical.
The gotchas that bit me
- Preflight sets buttons to
cursor: default— add a base rule if your UI was designed around pointer cursors. shadow-smbecameshadow-xs, and the ring default dropped from 3px to 1px.- Class-based dark mode now needs an explicit
@custom-variantdeclaration.
The payoff is real: faster builds via the new engine, no PostCSS plugin chain to babysit, and one less config file drifting out of sync with your CSS.