Tailwind CSS v4: The Complete Guide to CSS-First Configuration, Migration, and New Features

Noqta TeamAI Bot
By Noqta Team & AI Bot ·

Loading the Text to Speech Audio Player...

Tailwind CSS v4 is a ground-up rewrite. No more tailwind.config.js. No more content arrays. Everything lives in CSS now. This guide covers everything you need to know — whether you are starting fresh or migrating from v3.

What You Will Learn

By the end of this guide, you will:

  • Understand the architectural changes in Tailwind CSS v4
  • Configure your entire design system using the @theme directive in CSS
  • Set up Tailwind v4 with Next.js, Vite, and other frameworks
  • Migrate an existing v3 project to v4 step by step
  • Use new features: container queries, 3D transforms, @utility, @custom-variant
  • Build a custom design system with theme variables and CSS custom properties
  • Apply dark mode with the new class-based approach

Prerequisites

Before starting, ensure you have:

  • Node.js 18+ installed (node --version)
  • Basic CSS and HTML knowledge
  • Familiarity with Tailwind CSS concepts (utility classes, responsive design)
  • A code editor — VS Code with the Tailwind CSS IntelliSense extension recommended
  • A project to work with (we will set one up from scratch)

Why Tailwind CSS v4?

Tailwind CSS v4, released in January 2025, is not just an update — it is a complete rewrite. The team rebuilt the engine in Rust, replaced the JavaScript configuration system with native CSS, and added features developers have been requesting for years.

Here is what changed at a glance:

Areav3v4
Configurationtailwind.config.js (JavaScript)@theme directive (CSS)
Import syntax@tailwind base/components/utilities@import "tailwindcss"
Content detectionManual content: [...] arrayAutomatic (respects .gitignore)
Build speed~600ms full builds~120ms (5x faster)
Incremental buildsMillisecondsMicroseconds (100x faster)
EngineJavaScriptRust (Oxide engine)
CSS layersCustom implementationNative CSS @layer
Browser supportWideSafari 16.4+, Chrome 111+, Firefox 128+

Part 1: Setting Up Tailwind CSS v4

Vite gets the best performance with the dedicated Vite plugin — no PostCSS needed.

npm create vite@latest my-app -- --template react-ts
cd my-app
npm install tailwindcss @tailwindcss/vite

Update your Vite config:

// vite.config.ts
import { defineConfig } from "vite";
import react from "@vitejs/plugin-react";
import tailwindcss from "@tailwindcss/vite";
 
export default defineConfig({
  plugins: [react(), tailwindcss()],
});

Replace your CSS entry point:

/* src/index.css */
@import "tailwindcss";

That is it. No postcss.config.js, no tailwind.config.js, no autoprefixer. The Vite plugin handles everything.

With Next.js

Next.js uses PostCSS under the hood, so you need the PostCSS plugin:

npx create-next-app@latest my-app
cd my-app
npm install tailwindcss @tailwindcss/postcss

Update your PostCSS config:

// postcss.config.mjs
export default {
  plugins: {
    "@tailwindcss/postcss": {},
  },
};

Update your global CSS:

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

Remove tailwind.config.ts if it exists — you will not need it anymore.

Important: Remove autoprefixer from your PostCSS config. Tailwind v4 uses Lightning CSS internally, which handles vendor prefixing automatically.

With Other Frameworks

For Nuxt, SvelteKit, Astro, and Remix, use the Vite plugin (@tailwindcss/vite). For Angular or any PostCSS-based setup, use @tailwindcss/postcss. The CSS entry point is the same in all cases: @import "tailwindcss".


Part 2: CSS-First Configuration with @theme

This is the biggest paradigm shift in v4. Instead of writing a JavaScript config file, you define your entire design system in CSS using the @theme directive.

Basic Theme Configuration

/* app/globals.css */
@import "tailwindcss";
 
@theme {
  /* Colors — generates bg-brand, text-brand, border-brand, etc. */
  --color-brand: #3b82f6;
  --color-brand-light: #93c5fd;
  --color-brand-dark: #1e40af;
 
  /* Fonts — generates font-display, font-body */
  --font-display: "Cal Sans", "Inter", sans-serif;
  --font-body: "Inter", ui-sans-serif, system-ui, sans-serif;
 
  /* Spacing — generates p-18, m-18, gap-18, etc. */
  --spacing-18: 4.5rem;
  --spacing-128: 32rem;
 
  /* Breakpoints — generates 3xl: responsive variant */
  --breakpoint-3xl: 1920px;
 
  /* Shadows — generates shadow-soft */
  --shadow-soft: 0 2px 15px -3px rgb(0 0 0 / 0.07);
 
  /* Border radius — generates rounded-pill */
  --radius-pill: 9999px;
 
  /* Animations — generates animate-fade-in */
  --animate-fade-in: fade-in 0.5s ease-out;
 
  /* Easing — generates ease-spring */
  --ease-spring: cubic-bezier(0.175, 0.885, 0.32, 1.275);
}
 
@keyframes fade-in {
  from { opacity: 0; transform: translateY(-8px); }
  to { opacity: 1; transform: translateY(0); }
}

Every variable you define under @theme automatically generates the corresponding utility classes. You can use them immediately:

<h1 class="font-display text-brand text-4xl">Welcome</h1>
<p class="font-body text-gray-600">Body text here</p>
<div class="p-18 shadow-soft rounded-pill">Custom spacing and shadow</div>
<button class="animate-fade-in transition-all ease-spring">Smooth</button>

Theme Variable Namespaces

Here are all the namespaces Tailwind recognizes:

NamespaceWhat It GeneratesExample
--color-*All color utilities (bg, text, border, ring, etc.)--color-primary: #3b82f6
--font-*Font family utilities--font-sans: "Inter", sans-serif
--text-*Font size utilities--text-tiny: 0.625rem
--spacing-*Spacing utilities (p, m, gap, w, h, etc.)--spacing-18: 4.5rem
--breakpoint-*Responsive variants--breakpoint-3xl: 1920px
--shadow-*Box shadow utilities--shadow-glow: 0 0 20px ...
--radius-*Border radius utilities--radius-pill: 9999px
--animate-*Animation utilities--animate-spin: spin 1s linear infinite
--ease-*Transition timing utilities--ease-bounce: cubic-bezier(...)

Extending vs Overriding Defaults

By default, any variable you add extends the existing theme. To replace an entire namespace (removing all defaults), use the initial keyword:

@theme {
  /* Remove ALL default colors, keep only yours */
  --color-*: initial;
  --color-primary: oklch(0.6 0.2 260);
  --color-secondary: oklch(0.7 0.15 180);
  --color-neutral-50: #fafafa;
  --color-neutral-100: #f5f5f5;
  --color-neutral-900: #171717;
}

This is powerful for design systems where you want complete control over the available colors.

Using @theme inline

If you want theme variables available as utilities but not exposed as CSS custom properties in the output, use @theme inline:

@theme inline {
  --color-primary: #3b82f6;
}

The bg-primary and text-primary utilities will work, but var(--color-primary) will not be available in your custom CSS. This keeps your CSS output smaller.

Referencing Theme Values in Custom CSS

Theme variables are real CSS custom properties, so you can use them anywhere:

.custom-card {
  background: var(--color-brand);
  font-family: var(--font-display);
  padding: var(--spacing-6);
  border-radius: var(--radius-lg);
  box-shadow: var(--shadow-soft);
}

Part 3: New Features in v4

Container Queries (Built-in)

No plugin needed — container queries are now a core feature:

<!-- Mark an element as a container -->
<div class="@container">
  <div class="grid grid-cols-1 @sm:grid-cols-2 @lg:grid-cols-4 gap-4">
    <div class="p-4 bg-white rounded-lg shadow-sm">Card 1</div>
    <div class="p-4 bg-white rounded-lg shadow-sm">Card 2</div>
    <div class="p-4 bg-white rounded-lg shadow-sm">Card 3</div>
    <div class="p-4 bg-white rounded-lg shadow-sm">Card 4</div>
  </div>
</div>

The cards respond to the container's width, not the viewport. This is a game-changer for reusable components.

You can also use named containers:

<div class="@container/sidebar">
  <nav class="@md/sidebar:flex-col @md/sidebar:gap-4 flex gap-2">
    <!-- Responds to the sidebar container -->
  </nav>
</div>

And max-width container queries:

<div class="@container">
  <div class="@max-sm:flex-col flex gap-4">
    <!-- Stacks vertically when container is narrow -->
  </div>
</div>

3D Transform Utilities

Full 3D transform support out of the box:

<!-- Flip card effect -->
<div class="group perspective-800">
  <div class="relative transition-transform duration-500 group-hover:rotate-y-180"
       style="transform-style: preserve-3d;">
    <div class="absolute inset-0 backface-hidden bg-blue-500 rounded-xl p-6">
      <p class="text-white">Front of card</p>
    </div>
    <div class="absolute inset-0 backface-hidden rotate-y-180 bg-purple-500 rounded-xl p-6">
      <p class="text-white">Back of card</p>
    </div>
  </div>
</div>
 
<!-- Subtle 3D tilt -->
<div class="hover:rotate-x-2 hover:rotate-y-3 transition-transform duration-300">
  Interactive card with 3D tilt
</div>

Available 3D utilities: rotate-x-*, rotate-y-*, rotate-z-*, translate-z-*, scale-z-*, perspective-*, and perspective-origin-*.

Gradient Improvements

Radial and conic gradients are now built-in:

<!-- Radial gradient -->
<div class="bg-radial from-blue-500 to-purple-500 h-64 rounded-xl"></div>
 
<!-- Conic gradient (color wheel) -->
<div class="bg-conic from-red-500 via-yellow-500 to-green-500 h-64 rounded-full"></div>
 
<!-- Gradient position -->
<div class="bg-radial-[at_top_left] from-pink-500 to-transparent h-64"></div>

The @utility Directive

Create custom utilities that work exactly like built-in ones — with responsive variants, hover states, and IntelliSense support:

/* Static utility */
@utility content-auto {
  content-visibility: auto;
}
 
/* Now you can use: content-auto, hover:content-auto, md:content-auto */
/* Custom container utility (replacing v3's container config) */
@utility container {
  margin-inline: auto;
  padding-inline: 2rem;
  max-width: 80rem;
}
/* Text balance utility */
@utility text-balance {
  text-wrap: balance;
}
 
/* Scrollbar hiding utility */
@utility scrollbar-none {
  scrollbar-width: none;
  &::-webkit-scrollbar {
    display: none;
  }
}

The @custom-variant Directive

Create custom variants for advanced selectors:

/* Class-based dark mode */
@custom-variant dark (&:where(.dark, .dark *));
 
/* Data attribute variants */
@custom-variant theme-midnight (&:where([data-theme="midnight"] *));
 
/* State variants */
@custom-variant loading (&:where([data-loading="true"]));

Usage in HTML:

<div class="bg-white dark:bg-gray-900 dark:text-white">
  Dark mode support
</div>
 
<div class="theme-midnight:bg-indigo-950 theme-midnight:text-indigo-100">
  Custom theme
</div>
 
<button class="loading:opacity-50 loading:pointer-events-none" data-loading="true">
  Submit
</button>

The not-* Variant

Style elements based on the absence of a condition:

<!-- Dimmed when NOT hovered -->
<div class="not-hover:opacity-60 transition-opacity">
  Hover to reveal
</div>
 
<!-- Margin on all items except the last -->
<ul>
  <li class="not-last:mb-4">Item 1</li>
  <li class="not-last:mb-4">Item 2</li>
  <li class="not-last:mb-4">Item 3</li>
</ul>

The starting:* Variant

Animate elements on mount — no JavaScript needed:

<div class="starting:opacity-0 starting:scale-95 transition-all duration-300">
  This element fades and scales in when it appears
</div>
 
<!-- Dialog animation -->
<dialog class="starting:opacity-0 starting:translate-y-4 transition-all duration-200 backdrop:bg-black/50">
  <p>Smoothly animated dialog</p>
</dialog>

This uses the CSS @starting-style rule under the hood.

The inert Variant

Style inert (disabled) sections:

<div class="inert:opacity-30 inert:pointer-events-none" inert>
  This section is disabled and dimmed
</div>

field-sizing Utility

Auto-resize textareas to fit their content:

<textarea class="field-sizing-content border rounded-lg p-3"
          placeholder="This textarea grows with your content...">
</textarea>

Color Scheme Utility

Tell the browser to use dark-mode form controls and scrollbars:

<html class="scheme-dark">
  <!-- Native dark scrollbars, form controls, etc. -->
</html>

Part 4: Migrating from v3 to v4

Automated Migration

Tailwind provides an upgrade tool that handles most of the work:

npx @tailwindcss/upgrade

This tool will:

  • Update your dependencies
  • Convert tailwind.config.js to @theme in CSS
  • Rename deprecated utility classes in your templates
  • Update the import syntax

Run the upgrade tool first. It handles about 90% of the migration automatically. Then review and fix any edge cases manually.

Step 1: Update Dependencies

# Remove old packages
npm uninstall tailwindcss postcss autoprefixer @tailwindcss/container-queries
 
# For Vite-based projects
npm install tailwindcss @tailwindcss/vite
 
# For Next.js / PostCSS-based projects
npm install tailwindcss @tailwindcss/postcss

Step 2: Update CSS Entry Point

/* BEFORE (v3) */
@tailwind base;
@tailwind components;
@tailwind utilities;
 
/* AFTER (v4) */
@import "tailwindcss";

Step 3: Convert Config to @theme

Before (tailwind.config.js):

module.exports = {
  content: ["./src/**/*.{js,ts,jsx,tsx}"],
  darkMode: "class",
  theme: {
    extend: {
      colors: {
        brand: "#3b82f6",
        accent: "#8b5cf6",
      },
      fontFamily: {
        display: ["Satoshi", "sans-serif"],
      },
      borderRadius: {
        "4xl": "2rem",
      },
    },
  },
  plugins: [require("@tailwindcss/typography")],
};

After (in your CSS file):

@import "tailwindcss";
 
@plugin "@tailwindcss/typography";
 
@custom-variant dark (&:where(.dark, .dark *));
 
@theme {
  --color-brand: #3b82f6;
  --color-accent: #8b5cf6;
  --font-display: "Satoshi", sans-serif;
  --radius-4xl: 2rem;
}

Then delete tailwind.config.js.

Step 4: Update Renamed Utilities

Several utility names shifted to make room for new smaller sizes:

v3 Classv4 ClassWhy
shadow-smshadow-xsshadow-sm is now what shadow was
shadowshadow-smScale shifted down
blur-smblur-xsScale shifted down
blurblur-smScale shifted down
rounded-smrounded-xsScale shifted down
roundedrounded-smScale shifted down
outline-noneoutline-hiddenoutline-none now sets outline-style: none
ringring-3Default ring width changed

Step 5: Update Ring Defaults

In v3, ring was 3px wide and blue-500. In v4, ring is 1px wide and uses currentColor:

<!-- v3 -->
<button class="focus:ring focus:ring-offset-2">
 
<!-- v4 — specify width and color explicitly -->
<button class="focus:ring-3 focus:ring-blue-500 focus:ring-offset-2">

Step 6: Migrate space-x/y to gap

The space-x-* and space-y-* utilities still work but now use the :not(:last-child) selector instead of :not([hidden]) ~ :not([hidden]). For flex and grid layouts, prefer gap:

<!-- v3 pattern -->
<div class="flex flex-col space-y-4">
 
<!-- v4 recommended -->
<div class="flex flex-col gap-4">

Step 7: Load Plugins with @plugin

@plugin "@tailwindcss/typography";
@plugin "@tailwindcss/forms";
@plugin "./my-custom-plugin.js";

Step 8: Handle Content Detection

Tailwind v4 automatically detects your template files by scanning your project and respecting .gitignore. If you need to include files from node_modules or other ignored paths:

@source "../node_modules/@my-ui-lib/src/**/*.html";

To safelist specific utilities:

@source inline("underline bg-red-500 text-white");

Part 5: Building a Design System with v4

Let us build a practical design system for a SaaS application using all the new v4 features.

Step 1: Define the Theme

/* styles/globals.css */
@import "tailwindcss";
 
@custom-variant dark (&:where(.dark, .dark *));
 
@theme {
  /* Brand colors using oklch for perceptual uniformity */
  --color-primary-50: oklch(0.97 0.01 260);
  --color-primary-100: oklch(0.93 0.03 260);
  --color-primary-200: oklch(0.86 0.06 260);
  --color-primary-300: oklch(0.76 0.1 260);
  --color-primary-400: oklch(0.66 0.17 260);
  --color-primary-500: oklch(0.55 0.22 260);
  --color-primary-600: oklch(0.48 0.22 260);
  --color-primary-700: oklch(0.4 0.2 260);
  --color-primary-800: oklch(0.33 0.16 260);
  --color-primary-900: oklch(0.27 0.12 260);
 
  /* Neutral palette */
  --color-surface: #ffffff;
  --color-surface-raised: #f8fafc;
  --color-surface-overlay: #f1f5f9;
  --color-text: #0f172a;
  --color-text-muted: #64748b;
  --color-border: #e2e8f0;
 
  /* Typography */
  --font-sans: "Inter", ui-sans-serif, system-ui, sans-serif;
  --font-display: "Cal Sans", "Inter", sans-serif;
  --font-mono: "JetBrains Mono", ui-monospace, monospace;
 
  /* Shadows for elevation */
  --shadow-xs: 0 1px 2px 0 rgb(0 0 0 / 0.03);
  --shadow-sm: 0 1px 3px 0 rgb(0 0 0 / 0.06), 0 1px 2px -1px rgb(0 0 0 / 0.06);
  --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.07), 0 2px 4px -2px rgb(0 0 0 / 0.07);
  --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.07), 0 4px 6px -4px rgb(0 0 0 / 0.07);
  --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.08), 0 8px 10px -6px rgb(0 0 0 / 0.08);
 
  /* Motion */
  --ease-spring: cubic-bezier(0.175, 0.885, 0.32, 1.275);
  --ease-smooth: cubic-bezier(0.4, 0, 0.2, 1);
  --animate-fade-in: fade-in 0.4s var(--ease-smooth);
  --animate-slide-up: slide-up 0.3s var(--ease-spring);
  --animate-scale-in: scale-in 0.2s var(--ease-smooth);
}
 
@keyframes fade-in {
  from { opacity: 0; }
  to { opacity: 1; }
}
 
@keyframes slide-up {
  from { opacity: 0; transform: translateY(12px); }
  to { opacity: 1; transform: translateY(0); }
}
 
@keyframes scale-in {
  from { opacity: 0; transform: scale(0.95); }
  to { opacity: 1; transform: scale(1); }
}

Step 2: Create Custom Utilities

/* Custom utilities for the design system */
@utility text-balance {
  text-wrap: balance;
}
 
@utility scrollbar-none {
  scrollbar-width: none;
  &::-webkit-scrollbar {
    display: none;
  }
}
 
@utility glass {
  background: rgb(255 255 255 / 0.8);
  backdrop-filter: blur(12px) saturate(180%);
  border: 1px solid rgb(255 255 255 / 0.3);
}

Step 3: Use the Design System

<!-- Navigation with glass effect -->
<nav class="glass fixed top-0 inset-x-0 z-50">
  <div class="mx-auto max-w-7xl px-6 flex items-center justify-between h-16">
    <span class="font-display text-xl text-text">MyApp</span>
    <div class="flex gap-6">
      <a href="#" class="text-text-muted hover:text-primary-500 transition-colors">Features</a>
      <a href="#" class="text-text-muted hover:text-primary-500 transition-colors">Pricing</a>
    </div>
  </div>
</nav>
 
<!-- Hero section -->
<section class="pt-32 pb-20 px-6">
  <div class="mx-auto max-w-3xl text-center animate-fade-in">
    <h1 class="font-display text-5xl text-text text-balance">
      Build faster with the right tools
    </h1>
    <p class="mt-6 text-lg text-text-muted text-balance">
      Everything you need to ship your next project, without the complexity.
    </p>
    <div class="mt-10 flex justify-center gap-4">
      <button class="bg-primary-500 hover:bg-primary-600 text-white px-6 py-3 rounded-lg
                     shadow-md hover:shadow-lg transition-all ease-smooth font-medium">
        Get started
      </button>
      <button class="bg-surface-raised hover:bg-surface-overlay text-text px-6 py-3
                     rounded-lg border border-border transition-all ease-smooth font-medium">
        Learn more
      </button>
    </div>
  </div>
</section>
 
<!-- Feature cards with container queries -->
<section class="px-6 py-20">
  <div class="mx-auto max-w-6xl @container">
    <div class="grid grid-cols-1 @md:grid-cols-2 @xl:grid-cols-3 gap-6">
      <div class="bg-surface-raised border border-border rounded-xl p-6
                  hover:shadow-lg hover:-translate-y-1 transition-all ease-spring
                  animate-slide-up">
        <div class="w-10 h-10 bg-primary-100 text-primary-600 rounded-lg
                    flex items-center justify-center text-lg">

        </div>
        <h3 class="mt-4 font-display text-lg text-text">Lightning Fast</h3>
        <p class="mt-2 text-text-muted">
          Built on a Rust-powered engine for instant builds.
        </p>
      </div>
      <!-- More cards... -->
    </div>
  </div>
</section>

Part 6: Dark Mode in v4

Automatic (Media-Based)

By default, v4 uses prefers-color-scheme — no configuration needed:

<div class="bg-white dark:bg-gray-900 text-gray-900 dark:text-gray-100">
  Automatically follows system preference
</div>

Class-Based Dark Mode

For manual toggle control, add the custom variant:

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

Then toggle the .dark class on the <html> element:

// Toggle dark mode
document.documentElement.classList.toggle("dark");
 
// Or based on user preference with localStorage
const theme = localStorage.getItem("theme") || "system";
if (theme === "dark" || (theme === "system" && window.matchMedia("(prefers-color-scheme: dark)").matches)) {
  document.documentElement.classList.add("dark");
}

Using scheme-dark for Native Controls

For dark scrollbars and native form controls:

<html class="dark scheme-dark">
  <!-- Browser renders dark-themed scrollbars, checkboxes, etc. -->
</html>

Part 7: Advanced Patterns

Responsive Container Queries

Build truly responsive components that adapt to their container, not the viewport:

<div class="@container">
  <article class="flex @sm:flex-row flex-col gap-4">
    <img class="@sm:w-48 w-full rounded-lg object-cover" src="..." alt="..." />
    <div>
      <h2 class="font-display text-lg">Article Title</h2>
      <p class="@sm:block hidden text-text-muted mt-2">
        Description only visible in wider containers.
      </p>
    </div>
  </article>
</div>

Multi-Theme Support

Create multiple themes using @custom-variant:

@custom-variant theme-ocean (&:where([data-theme="ocean"] *));
@custom-variant theme-sunset (&:where([data-theme="sunset"] *));
@custom-variant theme-forest (&:where([data-theme="forest"] *));
<div data-theme="ocean">
  <div class="bg-white theme-ocean:bg-sky-50 theme-sunset:bg-orange-50 theme-forest:bg-green-50">
    This adapts to the active theme
  </div>
</div>

@source for Third-Party Libraries

When using component libraries installed via npm:

@source "../node_modules/@headlessui/react/dist/**/*.js";
@source "../node_modules/my-design-system/components/**/*.tsx";

Prefixing for Embedded Contexts

If you are embedding Tailwind in a context where class name collisions are possible (like a widget):

@import "tailwindcss" prefix(tw);

All utilities will be prefixed: tw:bg-blue-500, tw:flex, tw:p-4, etc.


Troubleshooting

Classes Not Being Detected

If your utilities are not being applied:

  1. Check that files are not in .gitignore (Tailwind skips ignored files)
  2. Add explicit sources: @source "../path/to/templates/**/*.html"
  3. For dynamic classes, safelist them: @source inline("bg-red-500 text-white")

PostCSS Conflicts

If you see errors with other PostCSS plugins:

// postcss.config.mjs — Tailwind should be the ONLY plugin
export default {
  plugins: {
    "@tailwindcss/postcss": {},
    // Remove autoprefixer — Tailwind v4 handles it
    // Remove postcss-import — Tailwind v4 handles it
  },
};

VS Code IntelliSense

Update the Tailwind CSS IntelliSense extension to the latest version. It supports v4's @theme directive and will autocomplete your custom utilities.

Browser Compatibility

If you need to support older browsers (Safari < 16.4, Chrome < 111):

  • Stay on Tailwind v3.4 for those projects
  • Or use a polyfill strategy for CSS @layer and container queries

Next Steps

Now that you understand Tailwind CSS v4, here is where to go next:

  • Build a component library using @theme and @utility for your team
  • Migrate existing projects one by one using npx @tailwindcss/upgrade
  • Explore container queries — they fundamentally change how you think about responsive design
  • Try oklch colors for perceptually uniform color palettes
  • Read the official docs at tailwindcss.com/docs for the complete utility reference

Conclusion

Tailwind CSS v4 is a leap forward. The CSS-first configuration eliminates the mental model split between JavaScript config and CSS utilities. The Rust engine makes builds nearly instant. And new features like container queries, 3D transforms, and @utility give you tools that previously required plugins or custom CSS.

The migration path is smooth — run the upgrade tool, review the changes, and you are running on v4. For new projects, you get a cleaner, faster, and more powerful setup from day one.

The best part? Your Tailwind knowledge transfers directly. Every utility class you know still works. You are just gaining a better foundation underneath.


Want to read more tutorials? Check out our latest tutorial on Building Multi-Agent AI Systems with n8n: A Comprehensive Guide to Intelligent Automation.

Discuss Your Project with Us

We're here to help with your web development needs. Schedule a call to discuss your project and how we can assist you.

Let's find the best solutions for your needs.

Related Articles