| |

Tailwind CSS 55 🎨 Upgrading from Legacy Tailwind Configurations to Modern CSS-First Standards (@tailwindcss/upgrade)

Tailwind CSS v4 is not an incremental release. It is a rewrite of the framework’s engine, configuration model, and utility system. The JavaScript configuration file that defined every project’s theme since v1 is no longer auto-detected. The three @tailwind directives that anchored every stylesheet are gone. Several utility names have changed, default colors have shifted, and the plugin API has been replaced. For a project with thousands of utility classes and a complex tailwind.config.js, a manual migration is a multi-day effort. The @tailwindcss/upgrade tool exists to automate most of that work, migrating configuration to CSS, renaming utilities across templates, and updating dependencies. Understanding what the tool does, what it cannot do, and how to verify its output is the difference between a smooth upgrade and a broken stylesheet.

Key point: The upgrade tool handles the mechanical migration, but it cannot understand your project’s intent. Complex plugin configurations, dynamic theme values, and custom variant functions require manual attention. Always run the tool on a clean git branch and review every change before committing.


Why the upgrade is structural

The configuration model changed. In v3, the tailwind.config.js file was the single source of truth for theme values, plugins, content paths, and variants. In v4, configuration moves into the CSS file using the @theme directive. Custom utilities use @utility. Custom variants use @custom-variant. The JavaScript config is no longer auto-detected; a project with a tailwind.config.js and no migration will build with default Tailwind, silently ignoring all customizations.

The directives changed. The three @tailwind base, @tailwind components, and @tailwind utilities directives are replaced by a single @import "tailwindcss" statement. The @layer at-rule is no longer hijacked by Tailwind; it uses native CSS cascade layers. Custom utilities written in @layer utilities do not work as true utilities in v4 and must be converted to @utility.

The utility taxonomy changed. Several utilities were renamed for scale consistency. shadow-sm becomes shadow-xs, shadow becomes shadow-sm, rounded-sm becomes rounded-xs, blur-sm becomes blur-xs, and outline-none becomes outline-hidden. The ring utility now defaults to 1px instead of 3px, and the old 3px behavior requires ring-3.

The color system changed. Borders and dividers now default to currentColor instead of gray-200. The default color palette uses OKLCH instead of HSL. Opacity utilities like bg-opacity-50 are replaced by slash syntax like bg-black/50.

The plugin system changed. The PostCSS plugin moved from tailwindcss to @tailwindcss/postcss. Autoprefixer is no longer needed because v4 handles prefixing internally. postcss-import is also redundant because v4 resolves imports itself. Custom variants registered via addVariant() are replaced by @custom-variant.


a. Running the upgrade tool

The upgrade tool is a one-shot command that modifies the project’s files. It must be run on a clean working tree so that any unwanted changes can be reviewed and reverted.

The command

npx @tailwindcss/upgrade

The tool requires Node.js 20 or higher. It should be run from the project root, where the package.json and tailwind.config.js live.

What the tool does

The tool performs five categories of change. First, it updates dependencies: tailwindcss, @tailwindcss/postcss, @tailwindcss/vite, @tailwindcss/cli, and prettier-plugin-tailwindcss are bumped to v4. Second, it migrates CSS files: @tailwind directives become @import "tailwindcss", @layer utilities blocks become @utility definitions, and @apply statements are updated to use renamed classes. Third, it converts tailwind.config.js to CSS: theme values become @theme entries, custom variants become @custom-variant, and plugin configurations become @plugin directives. Fourth, it updates template files: renamed utilities are replaced, arbitrary values are canonicalized, and variant order is normalized. Fifth, it updates the PostCSS configuration and removes autoprefixer.

The dry-run limitation

The tool does not have a dry-run mode. It modifies files in place. The only safety mechanism is version control. Before running the command, the working tree should be clean. After running, git diff shows every change the tool made, and any unwanted change can be reverted individually.

git checkout -b upgrade-tailwind-v4
npx @tailwindcss/upgrade
git diff

The PostCSS configuration update

For a PostCSS-based project, the tool replaces the tailwindcss plugin with @tailwindcss/postcss and removes autoprefixer and postcss-import. The new configuration is minimal.

// postcss.config.js (after upgrade)
module.exports = {
  plugins: {
    '@tailwindcss/postcss': {},
  },
};

For a Vite project, the tool installs @tailwindcss/vite and updates the Vite configuration. The PostCSS config can be removed entirely.

// vite.config.js (after upgrade)
import tailwindcss from '@tailwindcss/vite';

export default {
  plugins: [tailwindcss()],
};

The compatibility escape hatch

If the automated migration is too disruptive, v4 provides a compatibility layer. The @config directive loads a v3-style JavaScript config from the CSS file. This allows a project to adopt v4 without migrating the configuration immediately.

@import "tailwindcss";
@config "./tailwind.config.js";

The theme values from the JavaScript config are available, but the project does not benefit from the CSS-first model. The recommended path is to start with @config, gradually move values into @theme, and remove the JavaScript file when the migration is complete.


b. What the tool changes

The tool’s changes fall into three categories: CSS files, configuration, and templates. Each category has its own set of transformations.

CSS file changes

The @tailwind directives are replaced by a single @import. The @layer utilities blocks are converted to @utility definitions. The @layer components blocks are left in place but may need manual adjustment because they no longer interact with Tailwind’s variant system.

/* Before (v3) */
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer utilities {
  .tab-4 { tab-size: 4; }
}

/* After (v4) */
@import "tailwindcss";

@utility tab-4 {
  tab-size: 4;
}

The @apply statements inside custom CSS are updated to use the new utility names. If a project used @apply shadow-sm, it becomes @apply shadow-xs.

Configuration changes

The tailwind.config.js theme extensions become @theme entries. Each theme key maps to a CSS variable namespace. Colors become --color-*, spacing becomes --spacing-*, fonts become --font-*, and so on.

// Before (v3)
module.exports = {
  theme: {
    extend: {
      colors: { brand: '#3b82f6' },
      spacing: { '128': '32rem' },
    },
  },
};
/* After (v4) */
@theme {
  --color-brand: #3b82f6;
  --spacing-128: 32rem;
}

Dark mode configuration changes. The darkMode: 'class' option becomes a @custom-variant directive. The default dark variant now follows prefers-color-scheme, so a class-based toggle requires an explicit override.

/* After (v4) */
@custom-variant dark (&:where(.dark, .dark *));

Plugin configurations become @plugin directives. The typography plugin, for example, is loaded via CSS instead of JavaScript.

@plugin "@tailwindcss/typography";

Template changes

The tool scans all template files and replaces renamed utilities. It also canonicalizes arbitrary values to named values where possible. blur-[4px] becomes blur-xs, and h-[1lh] becomes h-lh.

The variant order is normalized. Stacked variants now apply left to right instead of right to left. The tool reverses the order of order-sensitive stacked variants.

<!-- Before (v3) -->
<div class="group-hover:focus:bg-blue-500">

<!-- After (v4) -->
<div class="focus:group-hover:bg-blue-500">

The ! important modifier moves from the front of the class to the end. !flex becomes flex!. The old syntax still works but is deprecated.


c. What the tool cannot do

The upgrade tool handles mechanical transformations. It cannot understand the intent behind complex configurations or custom code. Several categories of changes require manual migration.

Complex plugin configurations

The typography plugin’s configuration options cannot be automatically migrated. A project that customized prose classes through the plugin options must rewrite those customizations as CSS rules or as @utility definitions. The same applies to any plugin with a configuration object.

Custom variant functions

Variants registered via the JavaScript plugin API using addVariant() cannot be automatically converted. The tool attempts to migrate simple cases, but complex variant functions must be rewritten as @custom-variant directives.

// v3: addVariant('hocus', ['&:hover', '&:focus'])
// v4: @custom-variant hocus (&:hover, &:focus);

Dynamic theme values

If the tailwind.config.js computed theme values at build time using JavaScript logic, those values cannot be migrated to CSS. The CSS-first model does not execute JavaScript. The values must be resolved to static CSS variables or the computation must move elsewhere.

Content path configuration

The content array is removed in v4. Automatic content detection scans the project based on .gitignore rules. If the project excluded files that should be scanned, or included files that should be excluded, the @source directive must be used manually.

@import "tailwindcss";
@source "../packages/ui/src";

Safelist

The safelist option has no direct equivalent. Classes that must always be generated can be added to a @source inline(...) directive, but the syntax is different and must be written manually.

The @layer components behavior

Custom CSS in @layer components no longer works with Tailwind’s variant system. A class defined in @layer components cannot be used with hover: or lg:. If the project relies on this behavior, the classes must be converted to @utility definitions.


Complete Example Session

/* ============================================
   PART 1: BEFORE MIGRATION (v3)
   ============================================ */

/* tailwind.config.js */
module.exports = {
  darkMode: 'class',
  content: ['./src/**/*.{js,ts,jsx,tsx}'],
  theme: {
    extend: {
      colors: {
        brand: {
          DEFAULT: '#3b82f6',
          50: '#eff6ff',
          500: '#3b82f6',
          900: '#1e3a8a',
        },
      },
      fontFamily: { display: ['Inter', 'sans-serif'] },
    },
  },
  plugins: [require('@tailwindcss/typography')],
};

/* app.css */
@tailwind base;
@tailwind components;
@tailwind utilities;

@layer utilities {
  .tab-4 { tab-size: 4; }
}


/* ============================================
   PART 2: RUN THE UPGRADE
   ============================================ */

// git checkout -b upgrade-tailwind-v4
// npx @tailwindcss/upgrade
// git diff


/* ============================================
   PART 3: AFTER MIGRATION (v4 CSS)
   ============================================ */

/* app.css */
@import "tailwindcss";

@custom-variant dark (&:where(.dark, .dark *));

@plugin "@tailwindcss/typography";

@theme {
  --color-brand: #3b82f6;
  --color-brand-50: #eff6ff;
  --color-brand-500: #3b82f6;
  --color-brand-900: #1e3a8a;
  --font-display: "Inter", sans-serif;
}

@utility tab-4 {
  tab-size: 4;
}

/* tailwind.config.js is deleted. */


/* ============================================
   PART 4: RENAMED UTILITIES IN TEMPLATES
   ============================================ */

/* Before */
<input class="shadow-sm blur-sm rounded-sm ring ring-blue-500" />
<button class="outline-none focus:outline-none">Click</button>

/* After (tool-applied) */
<input class="shadow-xs blur-xs rounded-xs ring-3 ring-blue-500" />
<button class="outline-hidden focus:outline-hidden">Click</button>


/* ============================================
   PART 5: THE DARK MODE MIGRATION
   ============================================ */

/* v3: darkMode: 'class' in config */
/* v4: @custom-variant dark (&:where(.dark, .dark *)); */

/* The variant is declared in CSS, not JavaScript. */
/* The usage in templates is unchanged: <div class="dark:bg-gray-900"> */


/* ============================================
   PART 6: POSTCSS CONFIGURATION
   ============================================ */

/* Before */
module.exports = {
  plugins: {
    tailwindcss: {},
    autoprefixer: {},
  },
};

/* After */
module.exports = {
  plugins: {
    '@tailwindcss/postcss': {},
  },
};

/* autoprefixer and postcss-import are removed. */


/* ============================================
   PART 7: MANUAL WORK — PLUGIN CONFIG
   ============================================ */

/* v3 typography configuration cannot be auto-migrated. */

/* Before (tailwind.config.js) */
plugins: [
  require('@tailwindcss/typography')({
    className: 'wysiwyg',
  }),
],

/* After (v4, manual) — the plugin is loaded without options. */
@plugin "@tailwindcss/typography";

/* Custom prose classes must be defined manually. */
@utility wysiwyg {
  /* Custom styles */
}


/* ============================================
   PART 8: MANUAL WORK — SAFELIST
   ============================================ */

/* v3 */
safelist: ['bg-red-500', 'text-white'],

/* v4 — no direct equivalent. */
/* Option: generate the classes via a source file. */
/* Option: use @source inline(...) if supported. */


/* ============================================
   PART 9: VERIFICATION CHECKLIST
   ============================================ */

/*
[ ] All @tailwind directives replaced with @import "tailwindcss"
[ ] tailwind.config.js theme values present in @theme
[ ] Custom utilities converted to @utility
[ ] Dark mode variant declared with @custom-variant
[ ] Renamed utilities replaced in templates
[ ] Border colors explicitly set (currentColor default)
[ ] Ring utilities updated to ring-3 where 3px was intended
[ ] Plugin configurations migrated or manually rewritten
[ ] PostCSS config updated to @tailwindcss/postcss
[ ] Build succeeds with no unknown utility warnings
*/


/* ============================================
   PART 10: THE COMPATIBILITY PATH
   ============================================ */

/* If full migration is not immediately feasible: */
@import "tailwindcss";
@config "./tailwind.config.js";

/* The v3 config works, but the project does not gain */
/* the benefits of CSS-first configuration. */
/* Migrate incrementally: move theme values to @theme, */
/* remove them from the JS config, then delete the file. */

The ten parts progressed from the v3 baseline through the upgrade command, the migrated CSS, utility renames, dark mode, PostCSS, the manual work for plugins and safelist, verification, and the compatibility path. The same project ran through every part, showing what the tool does and where manual effort is required.


Quick Reference

Upgrade Tool Scope

CategoryAutomatedManual
@tailwind → @importYes—
Theme → @themeYes (simple)Complex values
Utility renamesYes—
Dark mode variantYes—
Plugin loadingYesPlugin configs
Custom variantsPartialComplex functions
SafelistNoManual
Content pathsAuto-detection@source overrides

Renamed Utilities

v3v4Reason
shadow-smshadow-xsScale consistency
shadowshadow-smScale consistency
rounded-smrounded-xsScale consistency
blur-smblur-xsScale consistency
ring (3px)ring-3Explicit width
outline-noneoutline-hiddenSemantic clarity

Default Changes

Propertyv3 Defaultv4 Default
Border colorgray-200currentColor
Ring width3px1px
Ring colorblue-500currentColor
Color formatHSLOKLCH
Placeholdergray-40050% text opacity

Pipeline Changes

v3v4
tailwindcss PostCSS plugin@tailwindcss/postcss
autoprefixer requiredBuilt-in
postcss-import requiredBuilt-in
tailwind.config.js auto-detectedNot auto-detected; use @config or migrate

Best Practices

✅ Do This:

# Run on a clean branch.
git checkout -b upgrade-tailwind-v4  # ✅

# Review every diff.
git diff  # ✅

# Update Node.js to 20+ before running.
node --version  # ✅

# Use @config for gradual migration.
@config "./tailwind.config.js";  # ✅

# Convert @layer utilities to @utility.
@utility tab-4 { tab-size: 4; }  # ✅

# Declare dark variant explicitly.
@custom-variant dark (&:where(.dark, .dark *));  # ✅

# Verify the build after upgrade.
npm run build  # ✅

❌ Don’t Do This:

# Don't run on uncommitted changes.
npx @tailwindcss/upgrade  # ❌ No rollback possible

# Don't assume the tool handles everything.
# Complex plugin configs require manual work.  # ❌

# Don't leave tailwind.config.js without @config.
# It is silently ignored in v4.  # ❌

# Don't use @layer utilities for variant-aware classes.
@layer utilities { .foo { ... } }  # ❌ Use @utility

# Don't skip the verification checklist.
# Renamed utilities break styles silently.  # ❌

Common Pitfalls

PitfallWhy It HappensFix
Config silently ignoredtailwind.config.js not auto-detectedMigrate to @theme or add @config
Utilities not renamedTool missed edge casesManual grep for renamed classes
Border colors wrongDefault changed to currentColorAdd explicit border colors
Ring width changedDefault changed from 3px to 1pxUse ring-3 where 3px intended
Plugin config lostComplex configs not auto-migratedRewrite as CSS or @utility
Dark mode brokendarkMode: 'class' no longer appliesAdd @custom-variant
Custom variants missingaddVariant() not auto-migratedRewrite as @custom-variant
Safelist classes absentNo safelist in v4Use @source or generate explicitly

Real-World Examples

1. Basic Upgrade Command

npx @tailwindcss/upgrade

2. The @import Replacement

/* v4 */
@import "tailwindcss";

3. The @theme Block

@theme {
  --color-brand: #3b82f6;
  --font-display: "Inter", sans-serif;
}

4. The @utility Directive

@utility tab-4 {
  tab-size: 4;
}

5. The @custom-variant for Dark Mode

@custom-variant dark (&:where(.dark, .dark *));

6. The @plugin Directive

@plugin "@tailwindcss/typography";

7. Renamed Utility Replacement

<!-- Before -->
<div class="shadow-sm ring outline-none">
<!-- After -->
<div class="shadow-xs ring-3 outline-hidden">

8. The Compatibility Escape

@import "tailwindcss";
@config "./tailwind.config.js";

9. Explicit Border Color

<!-- v4 requires explicit border color -->
<div class="border border-gray-200">

10. PostCSS Config Simplification

module.exports = {
  plugins: { '@tailwindcss/postcss': {} },
};

Visual

The Upgrade Flow

┌────────────────────────────────────────────────────────────┐
│  THE UPGRADE PROCESS                                       │
│                                                            │
│  ┌──────────────────────────────────────────────────┐     │
│  │  v3 Project                                       │     │
│  │    tailwind.config.js                             │     │
│  │    @tailwind base/components/utilities            │     │
│  │    @layer utilities { ... }                       │     │
│  └──────────────────────────────────────────────────┘     │
│                        │                                   │
│                        v                                   │
│  ┌──────────────────────────────────────────────────┐     │
│  │  npx @tailwindcss/upgrade                         │     │
│  │    - Updates dependencies                         │     │
│  │    - Migrates CSS files                           │     │
│  │    - Converts config to @theme                    │     │
│  │    - Renames utilities in templates               │     │
│  │    - Updates PostCSS config                       │     │
│  └──────────────────────────────────────────────────┘     │
│                        │                                   │
│                        v                                   │
│  ┌──────────────────────────────────────────────────┐     │
│  │  v4 Project (automated)                           │     │
│  │    @import "tailwindcss"                          │     │
│  │    @theme { ... }                                 │     │
│  │    @utility { ... }                               │     │
│  │    @custom-variant dark { ... }                   │     │
│  └──────────────────────────────────────────────────┘     │
│                        │                                   │
│                        v                                   │
│  ┌──────────────────────────────────────────────────┐     │
│  │  Manual work required                             │     │
│  │    - Plugin configs                               │     │
│  │    - Custom variant functions                     │     │
│  │    - Safelist                                     │     │
│  │    - Dynamic theme values                         │     │
│  └──────────────────────────────────────────────────┘     │
│                        │                                   │
│                        v                                   │
│  ┌──────────────────────────────────────────────────┐     │
│  │  Verification                                     │     │
│  │    - Build succeeds                               │     │
│  │    - Visual regression check                      │     │
│  │    - Renamed utilities applied                    │     │
│  └──────────────────────────────────────────────────┘     │
│                                                            │
└────────────────────────────────────────────────────────────┘

Configuration Migration

┌────────────────────────────────────────────────────────────┐
│  JS CONFIG → CSS @theme                                    │
│                                                            │
│  v3 (tailwind.config.js)                                   │
│  ┌──────────────────────────────────────────────────┐     │
│  │  theme: {                                         │     │
│  │    extend: {                                      │     │
│  │      colors: { brand: '#3b82f6' },                │     │
│  │      spacing: { '128': '32rem' },                 │     │
│  │      fontFamily: { display: ['Inter'] },          │     │
│  │    },                                             │     │
│  │  },                                               │     │
│  └──────────────────────────────────────────────────┘     │
│                        │                                   │
│                        v                                   │
│  v4 (app.css)                                              │
│  ┌──────────────────────────────────────────────────┐     │
│  │  @theme {                                         │     │
│  │    --color-brand: #3b82f6;                        │     │
│  │    --spacing-128: 32rem;                          │     │
│  │    --font-display: "Inter", sans-serif;           │     │
│  │  }                                                │     │
│  └──────────────────────────────────────────────────┘     │
│                                                            │
│  Namespace mapping:                                        │
│    colors      → --color-*                                 │
│    spacing     → --spacing-*                               │
│    fontFamily  → --font-*                                  │
│    borderRadius → --radius-*                               │
│                                                            │
└────────────────────────────────────────────────────────────┘

The Compatibility Path

┌────────────────────────────────────────────────────────────┐
│  GRADUAL MIGRATION WITH @config                            │
│                                                            │
│  STEP 1: Adopt v4 with compatibility layer                 │
│  ┌──────────────────────────────────────────────────┐     │
│  │  @import "tailwindcss";                           │     │
│  │  @config "./tailwind.config.js";                  │     │
│  │  (v3 config works, no CSS-first benefits)         │     │
│  └──────────────────────────────────────────────────┘     │
│                        │                                   │
│                        v                                   │
│  STEP 2: Move values to @theme incrementally               │
│  ┌──────────────────────────────────────────────────┐     │
│  │  @import "tailwindcss";                           │     │
│  │  @config "./tailwind.config.js";                  │     │
│  │  @theme {                                         │     │
│  │    --color-brand: #3b82f6;                        │     │
│  │  }                                                │     │
│  │  (Brand moved; rest still in JS config)           │     │
│  └──────────────────────────────────────────────────┘     │
│                        │                                   │
│                        v                                   │
│  STEP 3: Remove the JS config entirely                     │
│  ┌──────────────────────────────────────────────────┐     │
│  │  @import "tailwindcss";                           │     │
│  │  @theme {                                         │     │
│  │    --color-brand: #3b82f6;                        │     │
│  │    --font-display: "Inter", sans-serif;           │     │
│  │  }                                                │     │
│  │  (Full CSS-first configuration)                   │     │
│  └──────────────────────────────────────────────────┘     │
│                                                            │
│  @config is a bridge, not a destination.                   │
│                                                            │
└────────────────────────────────────────────────────────────┘

Utility Renames

┌────────────────────────────────────────────────────────────┐
│  RENAMED UTILITIES (AUTOMATED)                             │
│                                                            │
│  v3 Class          →  v4 Class                             │
│  ─────────────────────────────────────                     │
│  shadow-sm         →  shadow-xs                            │
│  shadow            →  shadow-sm                            │
│  rounded-sm        →  rounded-xs                           │
│  rounded           →  rounded-sm                           │
│  blur-sm           →  blur-xs                              │
│  blur              →  blur-sm                              │
│  ring (3px)        →  ring-3                               │
│  outline-none      →  outline-hidden                       │
│                                                            │
│  The tool replaces these across all template files.        │
│  Verify with grep after the upgrade.                       │
│                                                            │
└────────────────────────────────────────────────────────────┘

Summary

ItemValue
@tailwindcss/upgradeAutomated migration tool for v3 to v4
RequirementNode.js 20+, clean git branch
Configurationtailwind.config.js → @theme in CSS
Directives@tailwind → @import "tailwindcss"
Custom utilities@layer utilities → @utility
Custom variantsaddVariant() → @custom-variant
Pluginsrequire() → @plugin directive
PostCSStailwindcss → @tailwindcss/postcss
AutoprefixerRemoved; built into v4
Compatibility@config loads v3 JS config
Manual workPlugin configs, custom variants, safelist
Verificationgit diff and build test

Key takeaways:

  • The upgrade is structural, not cosmetic. v4 changes the configuration model, the directives, the utility taxonomy, the color system, and the plugin API. The tool automates the mechanical parts, but understanding the scope is necessary for verification.
  • Run on a clean branch. The tool modifies files in place with no dry-run mode. Version control is the only rollback mechanism. Review every diff before committing.
  • Configuration moves to CSS. The tailwind.config.js file is no longer auto-detected. Theme values become @theme entries, custom utilities become @utility, and custom variants become @custom-variant.
  • The tool handles simple cases, not complex ones. Plugin configurations, custom variant functions, dynamic theme values, and safelist entries require manual migration. The tool’s output is a starting point, not a finished upgrade.
  • Utility renames are the most visible change. shadow-sm becomes shadow-xs, ring becomes ring-3, outline-none becomes outline-hidden. These are replaced automatically, but verification is necessary.
  • Defaults changed. Borders default to currentColor, rings default to 1px and currentColor, and the color palette uses OKLCH. Explicit colors are required where the old defaults were relied upon.
  • @config is a bridge. A project that cannot migrate immediately can load its v3 JavaScript config with @config. The recommended path is incremental migration: move values to @theme one namespace at a time, then delete the JavaScript file.
  • Verify the build and the visuals. A successful build does not guarantee correct styling. Renamed utilities that were missed, border colors that default to currentColor, and ring widths that changed can all break layouts silently.

Remember: The @tailwindcss/upgrade tool automates the bulk of the v3 to v4 migration: it converts configuration to CSS, renames utilities, updates dependencies, and simplifies the PostCSS pipeline. It cannot understand intent. Complex plugin configurations, custom variant functions, and dynamic theme values require manual work. Run the tool on a clean branch, review every change, and treat the output as a starting point rather than a finished migration. The v4 model is CSS-first: configuration lives in @theme, custom utilities live in @utility, and custom variants live in @custom-variant. The JavaScript configuration file that anchored every project since v1 is no longer auto-detected, and a project that leaves it in place without @config will build with default Tailwind, silently ignoring every customization.



Stop using slow, ad-bloated tool sites! 🤮

🔎 Search “KandZ Tools” on Google to use many professional utilities for free.

KandZ.me is the ultimate minimalist hub for:
✅ Finance (Mortgage, Interest, Inflation)
✅ Tech (Base64, JSON, Dev Suite, IP)
✅ Health (BMI, BMR, TDEE)
✅ Productivity (Timer, Workspace, QR)

⚡️ Fast & Private
🔒 No data leaves your device
💎 100% Free

🔗 Use it now: https://tools.kandz.me
🔖 Bookmark it—you’ll need it later!