Skip to content
themes.dev
Free tool

Tailwind config to v4 converter

Paste your tailwind.config.js or .ts and get the v4 CSS that replaces it, with a list of what you still have to do by hand. Your config is read, never run, and never leaves your browser.

Try an example:
app.css 20 variables
@import "tailwindcss";

@theme {
  --color-brand-50: #eef4ff;
  --color-brand-100: #d9e6ff;
  --color-brand-500: #3e63dd;
  --color-brand-600: #2f4fc0;
  --color-brand-900: #172554;
  --color-brand: #3e63dd;

  --color-surface: rgb(var(--surface));

  --font-sans: Inter var, -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", "Noto Sans", Arial, sans-serif, "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", "Noto Color Emoji";
  --font-display: Satoshi, sans-serif;
  --font-display--font-feature-settings: "ss01";

  --text-2xs: 0.625rem;
  --text-2xs--line-height: 0.875rem;
  --text-hero: 4.5rem;
  --text-hero--line-height: 1;
  --text-hero--letter-spacing: -0.04em;
  --text-hero--font-weight: 600;

  --spacing-gutter: 1.5rem;

  --radius-4xl: 2rem;

  --shadow-card: 0 1px 2px rgb(0 0 0 / 0.05), 0 8px 24px -12px rgb(30 40 90 / 0.25);

  --breakpoint-3xl: 120rem;
}

Conversion report

  • Done for youImportsdefaultTheme.fontFamily.sans was filled in with the v4 default values from tailwindcss@4.
  • Done for youContentcontent isn't needed: v4 scans your project automatically, skipping .gitignore'd files, node_modules, binaries and CSS. Left out: ./src/**/*.{html,js,jsx,ts,tsx}.
  • Done for youColors<alpha-value> placeholders were removed: v4 applies opacity modifiers (bg-brand/50) to any color.
  • Done for youSpacing2 spacing values were left out because v4 already generates every multiple of --spacing (0.25rem), like p-18 and w-4.5.

All themes.dev themes are v4-ready.

Browse the library

Moving a config to v4

What changed between tailwind.config.js and the CSS-first setup, and where this converter stops.

What changes in v4

Tailwind CSS v4 moves configuration out of JavaScript and into your stylesheet. The @tailwind base; @tailwind components; @tailwind utilities; lines become one @import "tailwindcss";, and the theme becomes CSS variables inside @theme. Each variable's namespace decides which utilities it creates: --color-brand-500 gives you bg-brand-500, --font-display gives font-display, --breakpoint-3xl gives the 3xl: variant.

v3 config keyv4 variable
colors--color-*
fontFamily--font-*
fontSize--text-*, with --text-*--line-height
fontWeight--font-weight-*
letterSpacing / lineHeight--tracking-* / --leading-*
spacing--spacing (one base value) and --spacing-*
screens--breakpoint-*
maxWidth / containers--container-*
borderRadius--radius-*
boxShadow / dropShadow--shadow-* / --drop-shadow-*
transitionTimingFunction--ease-*
animation + keyframes--animate-* + @keyframes inside @theme

Everything around the theme has a directive now. Plugins load with @plugin. The content array is gone because v4 finds your templates by itself; @source adds paths it skips, like a UI package in node_modules, and @source inline() replaces the safelist. Class-based dark mode is a one-line @custom-variant dark (&:where(.dark, .dark *));. A prefix is set on the import and works like a variant: tw:flex instead of tw-flex.

Replacing a whole section in v3 (theme.colors instead of theme.extend.colors) maps to resetting the namespace: --color-*: initial; clears the default palette before your own colors are added.

When to use npx @tailwindcss/upgrade instead

If you are upgrading a real project, start with the official tool:

npx @tailwindcss/upgrade

It needs Node.js 20 or newer, and it's best run on a clean branch so you can review the diff. It updates your packages, migrates the config to CSS and also rewrites your templates: renamed utilities like shadow-sm to shadow-xs, the new prefix syntax and the moved ! for important. This converter does not touch your templates.

This page is useful before or after that: to see what your config becomes without installing anything, to convert a config from a theme or a snippet you don't have a project for, or when the upgrade tool kept your config behind @config because it found something it couldn't migrate.

What this converter can't do

  • It doesn't run your config. Functions, require() of your own files, presets and computed values are listed in the report. Theme functions that only call theme() are read and turned into var(--…), and flagged for a check.
  • It knows tailwindcss/colors and tailwindcss/defaultTheme and fills them in with the v4 values, which are OKLCH colors, not the v3 hex codes.
  • Inline plugins, corePlugins, separator, regex safelist patterns and important with a selector have no direct CSS equivalent. The report says what to do instead.
  • Paths in @source and @plugin are relative to your CSS file, not to the config, so check them after you paste.
  • TypeScript is read after stripping the usual satisfies Config and : Config annotations. Other type syntax gives a parse error with a line number.

For the colors themselves, the Tailwind colors page lists the palette with hex codes.

Questions

How do I convert tailwind.config.js to Tailwind CSS v4?

Move the theme into CSS. Replace the @tailwind directives with @import "tailwindcss", put your theme values in an @theme block as CSS variables (colors become --color-*, fontFamily becomes --font-*, screens become --breakpoint-*), load plugins with @plugin and write dark mode as @custom-variant. Paste your config into the converter above to get that CSS for your own file.

Can I keep my tailwind.config.js in v4?

Yes. Add @config "./tailwind.config.js"; to your CSS and v4 loads it, but it no longer finds the file on its own. The corePlugins, safelist and separator options are not supported that way. It works as a bridge; the CSS-first setup is where v4 is going.

Should I use this or npx @tailwindcss/upgrade?

Use the official upgrade tool when you are upgrading a whole project: it updates your dependencies, migrates the config and rewrites class names in your templates. Use this converter when you only want the CSS, want to see what your config turns into before you upgrade, or the upgrade tool kept your config with @config because it was too dynamic to migrate.

Is my config uploaded or run?

Neither. The converter runs in your browser and reads the file with a JavaScript parser. It never executes your config, so require() calls, functions and imported files are listed in the report instead of being run.

Why did some spacing values disappear?

v4 generates spacing from one --spacing variable (0.25rem by default), so p-18, w-128 and mt-4.5 work without a theme entry. Values like 18: "4.5rem" only repeated that scale, so the converter leaves them out. Named values like gutter stay.

What happens to plugins like @tailwindcss/typography and @tailwindcss/forms?

They become @plugin lines, with their options in a block. Both have v4 releases. Container queries and aspect ratio are built into v4, so those plugins are dropped. Plugins written inline in the config have to become @utility rules or their own file.