Upgrading from v3 to v4

The official upgrade tool updates dependencies, converts tailwind.config.js into @theme variables and rewrites renamed classes. It needs Node.js 20 2,131 + and refuses to run with uncommitted Git 1,932 changes; run it on a new branch.

Running the upgrade tool on a v3 projectShell
git switch -c tailwind-v4
npx @tailwindcss/upgrade
Output
≈ tailwindcss v4.3.3
│ ↳ Upgrading from Tailwind CSS `v3.4.19`
│ ↳ Migrated configuration file: `.\tailwind.config.js`
│ ↳ Migrated stylesheet: `.\src\input.css`
│ ↳ Updated package: `tailwindcss`
│ ↳ Migrated `.\src\index.html`
│ Verify the changes and commit them to your repository.

On this test project the tool replaced the three @tailwind directives with @import 'tailwindcss';, moved the custom color into @theme { --color-brand: #0369a1; }, deleted the config file and rewrote the template:

A template before and after the upgrade toolHTMLLive
<!-- v3 -->
<div class="rounded shadow bg-brand bg-opacity-50 !p-4">
  <input class="border outline-none flex-grow ring">
<!-- v4, as migrated -->
<div class="rounded-sm shadow-sm bg-brand bg-opacity-50 p-4!">
  <input class="border outline-hidden grow ring-3">
Key breaking changes from Tailwind CSS v3 5,202 to v4
v3 v4
shadow-sm, rounded-sm shadow-xs, rounded-xs
shadow, rounded shadow-sm, rounded-sm
bg-opacity-50 bg-black/50
bg-[--brand] bg-(--brand)
border: gray-200 border: currentColor
ring: 3px, blue-500 ring: 1px, currentColor

Review the diff rather than trusting it blindly. The run above left two problems:

Then check the page in a browser: buttons now get cursor: default, hover: applies only on devices that can hover, and variants stack left to right (*:first:pt-0). A JavaScript config you keep must be loaded with @config, and its corePlugins and safelist options are no longer supported.