| name | tailwindcss-performance |
| description | Tailwind CSS performance optimization including v4 improvements. PROACTIVELY activate for: (1) Tailwind v4 Oxide engine performance, (2) Lightning CSS minification, (3) reducing CSS bundle size, (4) content config tuning to avoid scanning unused files, (5) safelist for dynamic classes (without bloating), (6) production builds with @apply minimization, (7) critical CSS extraction, (8) HTTP caching of generated CSS, (9) avoiding @apply overuse (utility-first preferred), (10) PurgeCSS / content-detection edge cases. Provides: performance tuning checklist, Oxide engine notes, content config patterns, safelist guidance, and critical-CSS workflow. |
Tailwind CSS Performance Optimization
v4 Performance Improvements
Tailwind CSS v4 features a completely rewritten engine in Rust:
| Metric | v3 | v4 |
|---|
| Full builds | Baseline | Up to 5x faster |
| Incremental builds | Milliseconds | Microseconds (100x+) |
| Engine | JavaScript | Rust |
JIT (Just-In-Time) Compilation
How JIT Works
JIT generates styles on-demand as classes are discovered in your files:
- Scans source files for class names
- Generates only the CSS you use
- Produces minimal, optimized output
v4: Always JIT
Unlike v3, JIT is always enabled in v4—no configuration needed:
@import "tailwindcss";
Content Detection
Automatic Detection (v4)
v4 automatically detects template files—no content configuration required:
@import "tailwindcss";
Explicit Content (v4)
If automatic detection fails, specify sources explicitly:
@import "tailwindcss";
@source "./src/**/*.{html,js,jsx,ts,tsx,vue,svelte}";
@source "./components/**/*.{js,jsx,ts,tsx}";
Excluding Paths
@source not "./src/legacy/**";
Tree Shaking
How It Works
Tailwind's build process removes unused CSS:
Source: All possible utilities (~15MB+)
↓
Scan: Find used class names
↓
Output: Only used styles (~10-50KB typical)
Production Build
npm run build
NODE_ENV=production npx postcss input.css -o output.css
Dynamic Class Names
The Problem
Tailwind can't detect dynamically constructed class names:
const color = 'blue'
className={`text-${color}-500`}
const size = 'lg'
className={`text-${size}`}
Solutions
1. Use Complete Class Names
const colorClasses = {
blue: 'text-blue-500',
red: 'text-red-500',
green: 'text-green-500',
}
className={colorClasses[color]}
2. Use Data Attributes
<div data-color={color} className="data-[color=blue]:text-blue-500 data-[color=red]:text-red-500">
3. Safelist Classes
@source inline("text-blue-500 text-red-500 text-green-500");
4. CSS Variables
@theme {
--color-dynamic: oklch(0.6 0.2 250);
}
<div class="text-[var(--color-dynamic)]">Dynamic color</div>
Optimizing Transitions
Use Specific Transitions
<button class="transition-all duration-200">
<button class="transition-colors duration-200">
<button class="transition-transform duration-200">
<button class="transition-opacity duration-200">
GPU-Accelerated Properties
Prefer transform and opacity for smooth animations:
<div class="transform hover:scale-105 transition-transform">
<div class="opacity-100 hover:opacity-80 transition-opacity">
<div class="left-0 hover:left-4 transition-all">
CSS Variable Usage
Prefer Native Variables
In v4, use CSS variables directly instead of theme():
.element {
color: theme(colors.blue.500);
}
.element {
color: var(--color-blue-500);
}
Static Theme Values
For performance-critical paths:
@import "tailwindcss/theme.css" theme(static);
This inlines theme values instead of using CSS variables.
Build Optimization
Vite Configuration
import tailwindcss from '@tailwindcss/vite'
import { defineConfig } from 'vite'
export default defineConfig({
plugins: [tailwindcss()],
build: {
cssMinify: 'lightningcss',
rollupOptions: {
output: {
manualChunks: {
}
}
}
}
})
PostCSS with cssnano
export default {
plugins: {
'@tailwindcss/postcss': {},
cssnano: process.env.NODE_ENV === 'production' ? {} : false
}
}
Reducing Bundle Size
1. Avoid Unused Plugins
@plugin "@tailwindcss/typography";
2. Limit Color Palette
@theme {
--color-*: initial;
--color-primary: oklch(0.6 0.2 250);
--color-secondary: oklch(0.7 0.15 180);
--color-gray-100: oklch(0.95 0 0);
--color-gray-900: oklch(0.15 0 0);
}
3. Limit Breakpoints
@theme {
--breakpoint-2xl: initial;
--breakpoint-sm: 640px;
--breakpoint-md: 768px;
--breakpoint-lg: 1024px;
}
Caching Strategies
Development
- v4's incremental builds are already extremely fast
- No additional caching needed in most cases
CI/CD
- name: Cache node_modules
uses: actions/cache@v4
with:
path: node_modules
key: ${{ runner.os }}-node-${{ hashFiles('package-lock.json') }}
- name: Build
run: npm run build
Measuring Performance
Build Time Analysis
time npm run build
DEBUG=tailwindcss:* npm run build
Bundle Analysis
npm install -D vite-bundle-analyzer
npm run build -- --analyze
CSS Size Check
ls -lh dist/assets/*.css
gzip -c dist/assets/main.css | wc -c
Performance Checklist
Development
Production
Common Issues
| Issue | Solution |
|---|
| Large CSS output | Check for dynamic classes, safelist issues |
| Slow builds | Ensure v4, check file globs |
| Missing styles | Check content detection, class names |
| Slow animations | Use GPU-accelerated properties |
Lazy Loading CSS
For very large apps, consider code-splitting CSS:
const AdminPage = lazy(() =>
import('./admin.css').then(() => import('./AdminPage'))
)
Best Practices Summary
- Let JIT do its work - Don't safelist unnecessarily
- Use complete class names - Avoid dynamic concatenation
- Specific transitions - Not
transition-all
- GPU properties - Prefer
transform and opacity
- Minimal theme - Only define what you use
- Production builds - Always use production mode
- Measure - Check your actual CSS size