Tailwind CSS v4: A Complete Guide to the New Rewrite and Performance
Tired of slow builds and complex CSS? Discover Tailwind CSS v4, a complete rewrite with 100x faster builds and revolutionary CSS-first configuration.

Have you ever felt that frustration of waiting forever for CSS to compile? Or had to configure a bunch of JavaScript files just to customize a few colors? Today I want to share something that will completely change your development experience: Tailwind CSS v4 - a complete rewrite that brings builds up to 100x faster and a revolutionary CSS-first configuration.
By the end of this article, you will understand the fundamental changes in v4, how to migrate your existing projects, and master the new advanced patterns that this version offers.
What is Tailwind CSS v4?
Tailwind CSS v4 is not just an incremental update - it is a complete rewrite from scratch. Imagine taking everything that worked well in v3 and optimizing every aspect for performance, simplicity, and modern CSS features.
Why This Matters
Before we dive into the implementation, let's understand the problem we are solving:
<!-- ❌ Sem Tailwind v4 - problemas comuns --><!-- Builds lentos, configuracao complexa, CSS inchado --><div class="custom-card"> <h2 class="custom-title">Meu Card</h2> <p class="custom-description">Descricao aqui</p></div><!-- E lá no CSS... centenas de linhas de código personalizado --><!-- ✅ Com Tailwind v4 - solução limpa e rápida --><div class="bg-white rounded-lg shadow-lg p-6 @container"> <h2 class="text-xl font-bold @sm:text-2xl">Meu Card</h2> <p class="text-gray-600 mt-2">Descrição aqui</p></div>Why this transformation is valuable:
Brutal performance: incremental builds in microseconds
Zero configuration: works out-of-the-box
Modern CSS: uses cascade layers, color-mix(), @property
Automatic detection: finds your templates automatically
When Should You Use Tailwind v4?
Ideal use cases:
Supports current browsers like Safari 16.4+, Chrome 111+, Firefox 128+
Enables rapid iteration and instant builds for fast development
Delivers microsecond incremental build performance
Tailwind v4 excels in scenarios demanding modern features, speed, and agility.
Modern projects that support current browsers (Safari 16.4+, Chrome 111+, Firefox 128+)
Agile teams that need rapid iteration and instant builds
Design systems that require consistency and granular customization
Complex applications where build performance is critical
When NOT to use Tailwind v4:
Does not support IE or older Safari versions
Vanilla CSS is simpler for small projects
Teams hesitant to adopt utility-first CSS
Scenarios where Tailwind v4 may not be the best fit
Legacy browser support (IE, older versions of Safari)
Small projects where the simplicity of vanilla CSS is sufficient
Teams resistant to adopting utility-first CSS
Installation: Setting Up Your First Project
Let's build this step by step. I will show how each part works and why each decision matters.
Step 1: Simplified Installation
First, we need to install Tailwind v4. Here is how to do it in the most efficient way:
Option 1: New Project with Vite (Recommended)
# Criar novo projetonpm create vite@latest meu-projeto-tailwind -- --template react-tscd meu-projeto-tailwind# Instalar Tailwind CSS v4npm install tailwindcss@next @tailwindcss/vite@nextOption 2: Existing Project
# Para projetos existentesnpm install tailwindcss@next @tailwindcss/vite@nextHow to configure Vite:
// vite.config.jsimport { defineConfig } from 'vite'import react from '@vitejs/plugin-react'import tailwindcss from '@tailwindcss/vite'export default defineConfig({ plugins: [ react(), tailwindcss(), // ← Apenas uma linha! ],})Why this configuration works so well:
Zero configuration: no need to define content paths
Automatic detection: finds all relevant files
Native integration: maximum performance with Vite
Step 2: Revolutionary CSS-First Configuration
Now comes the coolest part - the new CSS-first configuration:
2.1: Single CSS File
First, let's create the base CSS file:
/* src/styles/globals.css */@import "tailwindcss";/* Configuração do tema diretamente em CSS */@layer theme { :root { /* Cores personalizadas */ --color-primary: oklch(0.7 0.15 240); --color-secondary: oklch(0.8 0.1 120); /* Espaçamentos customizados */ --spacing-xs: 0.125rem; --spacing-sm: 0.25rem; --spacing-md: 0.5rem; /* Tipografia */ --font-family-brand: 'Inter', system-ui, sans-serif; --font-size-huge: 4rem; }}/* Estilos base personalizados */@layer base { body { font-family: var(--font-family-brand); line-height: 1.6; } h1, h2, h3 { font-weight: 700; letter-spacing: -0.025em; }}Why this implementation is brilliant:
Native CSS variables: works with any library
Full IntelliSense: autocomplete in modern IDEs
Automatic typing: TypeScript understands the variables
2.2: Advanced Theme Configuration
Let's implement a more sophisticated theme system:
/* Configuração avançada de tema */@layer theme { :root { /* Sistema de cores OKLCH (wide-gamut) */ --color-brand-50: oklch(0.98 0.01 240); --color-brand-100: oklch(0.95 0.02 240); --color-brand-500: oklch(0.7 0.15 240); --color-brand-900: oklch(0.3 0.08 240); /* Breakpoints customizados */ --breakpoint-tablet: 48rem; --breakpoint-desktop: 64rem; --breakpoint-wide: 80rem; /* Sistema de sombras avançado */ --shadow-soft: 0 2px 8px oklch(0 0 0 / 0.08); --shadow-medium: 0 4px 16px oklch(0 0 0 / 0.12); --shadow-hard: 0 8px 32px oklch(0 0 0 / 0.16); } /* Dark mode com variáveis dinâmicas */ [data-theme="dark"] { --color-brand-50: oklch(0.2 0.01 240); --color-brand-100: oklch(0.25 0.02 240); --color-brand-500: oklch(0.8 0.15 240); --color-brand-900: oklch(0.95 0.08 240); }}Important differences of this approach:
OKLCH vs RGB: more vibrant and consistent colors
Dynamic variables: theme changes without JavaScript
Modular system: easy maintenance and extension
2.3: Custom Utilities
/* Utilitários personalizados */@layer utilities { .text-balance { text-wrap: balance; } .scroll-smooth { scroll-behavior: smooth; } /* Container queries personalizadas */ .container-card { container-type: inline-size; container-name: card; } /* Gradientes avançados */ .bg-brand-gradient { background: linear-gradient( 135deg, var(--color-brand-500), var(--color-brand-700) ); }}Step 3: First Component with Advanced Features
// components/Card.jsxexport function Card({ title, description, image }) { return ( <div className="@container bg-white dark:bg-gray-900 rounded-xl shadow-soft overflow-hidden"> {/* Header com gradient */} <div className="h-48 bg-brand-gradient relative"> <img src={image} alt={title} className="w-full h-full object-cover mix-blend-overlay" /> </div> {/* Content com container queries */} <div className="p-6 @md:p-8"> <h3 className="text-xl @md:text-2xl font-bold text-gray-900 dark:text-white"> {title} </h3> <p className="mt-3 text-gray-600 dark:text-gray-300 text-balance"> {description} </p> {/* Actions responsivas */} <div className="mt-6 flex flex-col @sm:flex-row gap-3"> <button className="btn-primary flex-1 @sm:flex-initial"> Ler mais </button> <button className="btn-secondary"> Compartilhar </button> </div> </div> </div> )}Why this architecture is powerful:
Container queries: component-based responsiveness
Automatic dark mode: no additional JavaScript
Optimized performance: automatically optimized CSS
A More Complex Example: Responsive Dashboard
Let's build something more realistic - a dashboard that demonstrates advanced v4 features:
Understanding the Problem
Before jumping into the code, let's understand what we are building:
// ❌ Abordagem ingênua - por que isso não funciona bemfunction Dashboard() { return ( <div className="dashboard-container"> {/* Layout fixo, sem responsividade inteligente */} <aside className="sidebar-fixed">...</aside> <main className="main-content">...</main> </div> )}// ✅ Nossa abordagem melhorada - o que vamos construirfunction Dashboard() { return ( <div className="@container min-h-screen bg-gray-50 dark:bg-gray-900"> <aside className="sidebar @lg:w-64 @container">...</aside> <main className="main @container">...</main> </div> )}Step-by-Step Implementation
Phase 1: Adaptive Layout with Container Queries
// components/Dashboard.jsxfunction Dashboard() { return ( <div className="@container min-h-screen bg-gray-50 dark:bg-gray-900"> {/* Navigation responsiva */} <nav className="sticky top-0 z-50 bg-white/80 dark:bg-gray-900/80 backdrop-blur-md border-b border-gray-200 dark:border-gray-700"> <div className="px-4 @md:px-6 @lg:px-8"> <div className="flex items-center justify-between h-16"> <Logo /> <UserMenu /> </div> </div> </nav> {/* Layout principal */} <div className="flex"> <Sidebar /> <MainContent /> </div> </div> )}Breaking this down:
Container queries: responsiveness based on the parent container
Backdrop blur: modern effects without JavaScript
Sticky navigation: optimized native behavior
Phase 2: Intelligent Sidebar
function Sidebar() { return ( <aside className="@container w-full @lg:w-64 @lg:flex-shrink-0"> <div className="h-full px-3 py-4 overflow-y-auto bg-white dark:bg-gray-800 @lg:border-r @lg:border-gray-200 @lg:dark:border-gray-700"> {/* Menu items com estados visuais */} <nav className="space-y-2"> {menuItems.map((item) => ( <MenuItem key={item.id} item={item} className="group flex items-center px-3 py-2 text-sm font-medium rounded-lg hover:bg-gray-100 dark:hover:bg-gray-700 data-[active]:bg-brand-500 data-[active]:text-white transition-all duration-200 ease-in-out" /> ))} </nav> {/* Status indicator */} <div className="mt-8 p-4 rounded-lg bg-gradient-to-r from-brand-500 to-brand-600"> <StatusWidget /> </div> </div> </aside> )}Phase 3: Adaptive Card Grid
function MainContent() { return ( <main className="flex-1 @container"> <div className="p-4 @md:p-6 @lg:p-8"> {/* Header com stats */} <div className="mb-8"> <h1 className="text-2xl @md:text-3xl font-bold text-gray-900 dark:text-white"> Dashboard </h1> {/* Stats grid responsivo */} <div className="mt-6 grid grid-cols-1 @sm:grid-cols-2 @lg:grid-cols-4 gap-4"> {stats.map((stat) => ( <StatCard key={stat.id} stat={stat} /> ))} </div> </div> {/* Main content grid */} <div className="grid grid-cols-1 @lg:grid-cols-3 gap-6"> <div className="@lg:col-span-2"> <ChartSection /> </div> <div> <ActivityFeed /> </div> </div> </div> </main> )}Why this architecture is powerful:
Container-based breakpoints: each component adapts to its space
Flexible grid system: layouts that truly respond
Optimized performance: minimal CSS, maximum cache hit
Advanced Pattern: Dynamic Design Tokens System
Now let's explore an advanced pattern that demonstrates the true power of v4.
The Problem with Simple Approaches
/* ❌ Limitações da abordagem simples */.button { background: #3b82f6; /* Cor hard-coded */ color: white; padding: 0.5rem 1rem; /* Valores fixos */}Why this becomes problematic:
Lack of consistency: arbitrary colors and spacings
Maintenance difficulty: changes require updates in multiple places
No adaptability: does not respond to theme changes
Building the Advanced Solution
Stage 1: Semantic Design Tokens
/* Sistema de design tokens completo */@layer theme { :root { /* Tokens primitivos */ --color-blue-50: oklch(0.97 0.013 240); --color-blue-500: oklch(0.7 0.15 240); --color-blue-900: oklch(0.35 0.08 240); /* Tokens semânticos */ --color-primary: var(--color-blue-500); --color-primary-hover: var(--color-blue-600); --color-surface: var(--color-gray-50); --color-on-surface: var(--color-gray-900); /* Sistema de espaçamento baseado em escala */ --spacing-unit: 0.25rem; /* 4px */ --spacing-1: calc(var(--spacing-unit) * 1); /* 4px */ --spacing-2: calc(var(--spacing-unit) * 2); /* 8px */ --spacing-4: calc(var(--spacing-unit) * 4); /* 16px */ /* Tipografia responsiva */ --text-xs: 0.75rem; --text-sm: 0.875rem; --text-base: 1rem; --text-lg: 1.125rem; /* Shadows com color-mix */ --shadow-color: color-mix(in oklch, var(--color-primary) 20%, transparent); --shadow-sm: 0 1px 2px var(--shadow-color); --shadow-md: 0 4px 6px var(--shadow-color); }}Stage 2: Components with Visual States
@layer components { /* Sistema de botões baseado em tokens */ .btn { /* Base styles usando tokens */ padding: var(--spacing-2) var(--spacing-4); border-radius: calc(var(--spacing-unit) * 1.5); font-size: var(--text-sm); font-weight: 500; transition: all 0.2s ease-in-out; /* Estados visuais com color-mix */ &:hover { transform: translateY(-1px); box-shadow: var(--shadow-md); } &:active { transform: translateY(0); } /* Variantes */ &.btn-primary { background: var(--color-primary); color: white; &:hover { background: color-mix(in oklch, var(--color-primary) 90%, black); } } &.btn-secondary { background: var(--color-surface); color: var(--color-on-surface); border: 1px solid color-mix(in oklch, var(--color-on-surface) 20%, transparent); &:hover { background: color-mix(in oklch, var(--color-surface) 95%, var(--color-on-surface)); } } }}Stage 3: Adaptive Theme System
// hooks/useTheme.jsexport function useTheme() { const [theme, setTheme] = useState('light') useEffect(() => { document.documentElement.dataset.theme = theme }, [theme]) return { theme, setTheme }}// components/ThemeProvider.jsxexport function ThemeProvider({ children }) { const { theme } = useTheme() return ( <div data-theme={theme} className="theme-provider"> {children} </div> )}Why this architecture is powerful:
Scalable system: easy to add new themes and variants
Native performance: uses native CSS features for maximum speed
Maintainability: centralized changes propagate automatically
Tailwind v4 with TypeScript
For TypeScript users, here is how to make everything type-safe:
Configuring Types
// types/theme.tsexport interface ThemeConfig { colors: { primary: string secondary: string surface: string 'on-surface': string } spacing: { xs: string sm: string md: string lg: string xl: string } typography: { fontFamily: { brand: string[] mono: string[] } fontSize: { xs: string sm: string base: string lg: string } }}// Augment do módulo CSSdeclare module 'csstype' { interface Properties { '--color-primary'?: string '--color-secondary'?: string '--spacing-unit'?: string }}Implementation with Proper Typing
// components/Button.tsxinterface ButtonProps { variant: 'primary' | 'secondary' | 'outline' size: 'sm' | 'md' | 'lg' children: React.ReactNode onClick?: () => void disabled?: boolean}export function Button({ variant = 'primary', size = 'md', children, onClick, disabled = false }: ButtonProps) { const baseClasses = 'btn transition-all duration-200 focus:outline-none focus:ring-2 focus:ring-primary/50' const variantClasses = { primary: 'btn-primary', secondary: 'btn-secondary', outline: 'btn-outline' } const sizeClasses = { sm: 'px-3 py-1.5 text-sm', md: 'px-4 py-2 text-base', lg: 'px-6 py-3 text-lg' } return ( <button className={cn( baseClasses, variantClasses[variant], sizeClasses[size], disabled && 'opacity-50 cursor-not-allowed' )} onClick={onClick} disabled={disabled} > {children} </button> )}Advanced TypeScript Patterns
// utils/classNames.tstype ClassValue = string | number | boolean | undefined | nulltype ClassArray = ClassValue[]type ClassRecord = Record<string, any>export function cn(...classes: (ClassValue | ClassArray | ClassRecord)[]): string { return classes .flat() .filter(Boolean) .join(' ')}// Typed theme hookexport function useTypedTheme(): ThemeConfig { const [config, setConfig] = useState<ThemeConfig>(defaultTheme) const updateTheme = useCallback((updates: Partial<ThemeConfig>) => { setConfig(prev => ({ ...prev, ...updates })) }, []) return { ...config, updateTheme }}Advanced Patterns and Best Practices
1. Container Queries For Truly Responsive Components
What it solves: Responsiveness based on component size, not viewport
How it works: Uses native CSS @container queries
// components/ResponsiveCard.jsxfunction ResponsiveCard({ data }) { return ( <div className="@container bg-white rounded-lg overflow-hidden shadow-md"> <div className="grid grid-cols-1 @md:grid-cols-2 @lg:grid-cols-3"> <div className="p-4 @md:p-6"> <h3 className="text-lg @md:text-xl @lg:text-2xl font-bold"> {data.title} </h3> <p className="mt-2 text-sm @md:text-base text-gray-600"> {data.description} </p> </div> <div className="@md:col-span-1 @lg:col-span-2"> <img src={data.image} alt={data.title} className="w-full h-48 @md:h-full object-cover" /> </div> </div> </div> )}When to use: Components that need to adapt to available space, not screen size
2. Animations with @starting-style
The problem: Entry animations required JavaScript
The solution: native CSS @starting-style
@layer utilities { .animate-in { animation: fade-in 0.3s ease-out; } @keyframes fade-in { from { opacity: 0; transform: translateY(10px); } to { opacity: 1; transform: translateY(0); } } /* Para elementos que aparecem dinamicamente */ .fade-in-starting { @starting-style { opacity: 0; transform: translateY(10px); } opacity: 1; transform: translateY(0); transition: all 0.3s ease-out; }}Benefits: Smooth animations without additional JavaScript
3. Color System with Wide-Gamut (OKLCH)
Use case: More vibrant and consistent colors
@layer theme { :root { /* OKLCH oferece cores mais consistentes */ --color-brand-primary: oklch(0.7 0.15 240); /* Azul vibrante */ --color-brand-secondary: oklch(0.8 0.12 120); /* Verde consistente */ /* Variações automáticas com color-mix */ --color-brand-primary-light: color-mix(in oklch, var(--color-brand-primary) 80%, white); --color-brand-primary-dark: color-mix(in oklch, var(--color-brand-primary) 80%, black); }}Advantages: More vibrant colors, especially on modern displays
4. Layout with CSS Layers
Background: Precise control of style specificity
/* Definição das camadas */@layer theme, base, components, utilities;@layer theme { /* Variáveis de tema */ :root { --primary: oklch(0.7 0.15 240); }}@layer base { /* Reset e estilos base */ *, *::before, *::after { box-sizing: border-box; }}@layer components { /* Componentes reutilizáveis */ .card { background: white; border-radius: 0.5rem; box-shadow: 0 1px 3px rgba(0,0,0,0.1); }}@layer utilities { /* Utilitários do Tailwind */ .text-primary { color: var(--primary); }}Trade-offs: Greater control vs additional complexity
Common Pitfalls to Avoid
1. Unnecessarily Complex Configuration
The problem: Overengineering in CSS configuration
/* ❌ Não faça isso - configuração excessiva */@layer theme { :root { --color-red-50: #fef2f2; --color-red-100: #fee2e2; --color-red-200: #fecaca; /* ... 47 variações de vermelho */ --color-red-950: #450a0a; /* Centenas de variáveis desnecessárias */ --spacing-0-5: 0.125rem; --spacing-1-5: 0.375rem; --spacing-2-5: 0.625rem; }}/* ✅ Faça isso - configuração focada */@layer theme { :root { /* Apenas as cores que você realmente usa */ --color-primary: oklch(0.7 0.15 240); --color-secondary: oklch(0.8 0.1 120); --color-danger: oklch(0.65 0.15 15); /* Sistema de espaçamento simples */ --spacing-unit: 0.25rem; }}Why this matters: Excessive configuration makes the project difficult to maintain and understand
2. Abuse of Container Queries
Common error: Using @container for everything
Why it happens: Excitement about the new feature
// ❌ Evite este padrão - container queries desnecessáriasfunction SimpleText({ text }) { return ( <div className="@container"> <p className="text-base @sm:text-lg @md:text-xl"> {text} </p> </div> )}// ✅ Abordagem preferida - use quando realmente necessáriofunction ComplexCard({ data }) { return ( <div className="@container card-layout"> {/* Container query faz sentido aqui */} <div className="grid grid-cols-1 @lg:grid-cols-2"> <Content data={data} /> <Sidebar /> </div> </div> )}Prevention: Use container queries only when the component layout truly needs to adapt to its container
3. Ignoring Browser Support
The trap: Assuming all users have modern browsers
/* ❌ Problema - recursos sem fallback */.modern-only { background: color-mix(in oklch, blue 50%, red); container-type: inline-size;}/* ✅ Solução - progressive enhancement */.progressive { /* Fallback para navegadores antigos */ background: #6b46c1; /* Enhancement para navegadores modernos */ background: color-mix(in oklch, blue 50%, red);}@supports (container-type: inline-size) { .progressive { container-type: inline-size; }}Warning signs: CSS that breaks completely in older browsers
When NOT to Use Tailwind v4
Do not reach for Tailwind v4 when:
Legacy browser support: If you need to support IE or very old versions of Safari
Ultra-simple projects: A static landing page might not justify the complexity
Unfamiliar teams: If the team has no experience with utility-first CSS
<!-- ❌ Overkill para cenários simples --><div class="@container bg-white rounded-lg shadow-md p-4 @md:p-6 @lg:p-8"> <h1 class="text-xl @md:text-2xl @lg:text-3xl">Olá Mundo</h1></div><!-- ✅ Solução simples é melhor --><div class="simple-hello"> <h1>Olá Mundo</h1></div>Decision framework: Use Tailwind v4 when you need a consistent design system, fast builds, and modern CSS features
Tailwind v4 vs Alternatives
When Tailwind v4 Shines
Tailwind v4 is great for:
Complex design systems: Granular customization and consistency
Critical performance: Ultra-fast builds and optimized CSS
Large teams: Consistent patterns and maintainability
When to Consider Alternatives
Consider alternatives when you need:
Complex design systems requiring granular customization and consistency
Critical performance with ultra-fast builds and optimized CSS
Large teams needing consistent patterns and maintainability
Rapid prototyping with ready-to-use components (Bootstrap)
Minimal CSS for very simple projects (Vanilla CSS)
Runtime styling for complex dynamic styles (Styled-components)
Rapid prototyping → Bootstrap: Ready-to-use components
Minimal CSS → Vanilla CSS: For very simple projects
Runtime styling → Styled-components: For complex dynamic styling
Comparison Matrix
Feature | Tailwind v4 | Bootstrap | Styled-Components |
|---|---|---|---|
Build Performance | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐ |
Customization | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ |
Learning Curve | ⭐⭐⭐ | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ |
Final Size | ⭐⭐⭐⭐⭐ | ⭐⭐⭐ | ⭐⭐⭐ |
Modern Features | ⭐⭐⭐⭐⭐ | ⭐⭐ | ⭐⭐⭐⭐ |
Conclusion
Tailwind CSS v4 is a genuine revolution in interface development. It brings builds up to 100x faster, intuitive CSS-first configuration, and next-gen CSS features like container queries and wide-gamut colors.
Key takeaways:
Revolutionary performance: Incremental builds in microseconds transform your development experience
Simplified configuration: CSS-first eliminates the complexity of JavaScript config
Modern features: Container queries, OKLCH colors, and @starting-style open up new creative possibilities
Easier migration: Automatic upgrade tool makes the transition painless
Next time you start a project or consider optimizing your development stack, remember Tailwind v4. Your future self (and your team) will thank you for the speed, consistency and power it offers.
Next steps:
Install Tailwind v4 in a test project
Try Tailwind Play to test features
Read the official documentation to dive deeper
Have you tried Tailwind v4 in your projects yet? What patterns did you find most useful? Share your experiences in the comments!
If this article helped you master Tailwind v4, follow for more content on modern development and best practices! 🚀


