| name | tailwind-performance |
| description | Use when optimizing Tailwind CSS for production, reducing bundle size, and improving performance. Covers PurgeCSS, JIT mode, and build optimization. |
| allowed-tools | Read, Write, Edit, Bash, Grep, Glob |
Tailwind CSS - Performance Optimization
Tailwind CSS includes powerful tools for optimizing your CSS for production, ensuring fast load times and minimal bundle sizes.
Key Concepts
Just-In-Time (JIT) Mode
JIT mode (default since Tailwind 3.0) generates styles on-demand as you author your templates:
Benefits:
- Lightning-fast build times
- All variants enabled by default
- Arbitrary value support
- Smaller development builds
- No separate production build needed
// tailwind.config.js (JIT is default, no config needed)
module.exports = {
content: ['./src/**/*.{html,js,jsx,ts,tsx}'],
// JIT mode is automatic
}
Content Configuration
Proper content paths are critical for performance:
module.exports = {
content: [
'./src/**/*.{js,jsx,ts,tsx}',
'./pages/**/*.{js,jsx,ts,tsx}',
'./components/**/*.{js,jsx,ts,tsx}',
'./app/**/*.{js,jsx,ts,tsx}',
// Include any files that contain Tailwind classes
'./public/index.html',
],
}
Best Practices
1. Optimize Content Paths
Be specific to avoid scanning unnecessary files:
// Good: Specific paths
module.exports = {
content: [
'./src/**/*.{js,jsx,ts,tsx}',
'./components/**/*.{js,jsx,ts,tsx}',
],
}
// Bad: Too broad
module.exports = {
content: [
'./**/*.{js,jsx,ts,tsx}', // Scans node_modules!
],
}
2. Use Safelist for Dynamic Classes
When class names are constructed dynamically, use safelist:
module.exports = {
content: ['./src/**/*.{js,jsx,ts,tsx}'],
safelist: [
'bg-red-500',
'bg-green-500',
'bg-blue-500',
// Or use patterns
{
pattern: /bg-(red|green|blue)-(400|500|600)/,
variants: ['hover', 'focus'],
},
],
}
3. Avoid String Concatenation
Don't construct class names dynamically:
// Bad: These classes won't be detected
<div className={`text-${size}`}>
<div className={`bg-${color}-500`}>
// Good: Use complete class names
<div className={size === 'large' ? 'text-lg' : 'text-sm'}>
<div className={color === 'red' ? 'bg-red-500' : 'bg-blue-500'}>
// Or use safelist for dynamic values
4. Minimize Custom CSS
Rely on utilities to reduce overall CSS size:
/* Bad: Custom CSS that duplicates utilities */
.my-button {
background-color: #3b82f6;
color: white;
padding: 0.5rem 1rem;
border-radius: 0.375rem;
}
/* Good: Use utilities or @apply */
@layer components {
.my-button {
@apply bg-blue-500 text-white px-4 py-2 rounded-md;
}
}
/* Better: Component abstraction (no custom CSS) */
5. Enable CSS Minification
Ensure your build process minifies CSS:
// postcss.config.js
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
...(process.env.NODE_ENV === 'production' ? { cssnano: {} } : {})
},
}
6. Use CSS Variables Strategically
Combine Tailwind with CSS variables for theme switching without bloat:
:root {
--color-primary: 59 130 246; /* RGB */
}
[data-theme='dark'] {
--color-primary: 96 165 250;
}
// tailwind.config.js
module.exports = {
theme: {
extend: {
colors: {
primary: 'rgb(var(--color-primary) / <alpha-value>)',
},
},
},
}
Build Optimization
Vite Configuration
// vite.config.js
import { defineConfig } from 'vite'
export default defineConfig({
css: {
postcss: './postcss.config.js',
},
build: {
cssMinify: 'esbuild', // Fast CSS minification
rollupOptions: {
output: {
manualChunks: {
// Separate vendor chunks
vendor: ['react', 'react-dom'],
},
},
},
},
})
Next.js Configuration
// next.config.js
module.exports = {
experimental: {
optimizeCss: true, // Enable CSS optimization
},
// Next.js automatically optimizes Tailwind
}
Webpack Configuration
// webpack.config.js
const MiniCssExtractPlugin = require('mini-css-extract-plugin')
const CssMinimizerPlugin = require('css-minimizer-webpack-plugin')
module.exports = {
optimization: {
minimizer: [
new CssMinimizerPlugin(),
],
},
plugins: [
new MiniCssExtractPlugin({
filename: '[name].[contenthash].css',
}),
],
}
Performance Patterns
1. Code Splitting
Split CSS by route or component:
// Using dynamic imports
const HeavyComponent = lazy(() => import('./HeavyComponent'))
// Tailwind classes in HeavyComponent will be in a separate chunk
2. Critical CSS
Extract critical CSS for above-the-fold content:
<!DOCTYPE html>
<html>
<head>
<style>
/* Inline critical CSS */
.hero { /* ... */ }
.nav { /* ... */ }
</style>
<!-- Load full CSS async -->
<link rel="preload" href="/styles.css" as="style" onload="this.onload=null;this.rel='stylesheet'">
<noscript><link rel="stylesheet" href="/styles.css"></noscript>
</head>
3. Lazy Load Non-Critical Styles
// Load additional styles when needed
if (shouldLoadDarkMode) {
import('./dark-mode.css')
}
4. Font Optimization
// tailwind.config.js
module.exports = {
theme: {
extend: {
fontFamily: {
sans: [
'Inter var',
'system-ui',
'-apple-system',
'BlinkMacSystemFont',
'"Segoe UI"',
'Roboto',
'sans-serif',
],
},
},
},
}
/* Use font-display for better loading */
@font-face {
font-family: 'Inter var';
font-style: normal;
font-weight: 100 900;
font-display: swap; /* Prevent invisible text */
src: url('/fonts/inter-var.woff2') format('woff2');
}
Monitoring Performance
Bundle Size Analysis
# Analyze CSS bundle size
npx tailwindcss -i ./src/input.css -o ./dist/output.css --minify
# Check file size
ls -lh dist/output.css
# Detailed analysis with webpack-bundle-analyzer
npm install --save-dev webpack-bundle-analyzer
Lighthouse Metrics
Target metrics:
- First Contentful Paint (FCP): < 1.8s
- Largest Contentful Paint (LCP): < 2.5s
- Cumulative Layout Shift (CLS): < 0.1
- CSS Bundle Size: < 50KB (gzipped)
Performance Checklist
✅ Content paths are specific and optimized
✅ JIT mode is enabled (default in Tailwind 3+)
✅ CSS is minified in production
✅ Unused styles are purged
✅ Dynamic classes use safelist
✅ Critical CSS is inlined
✅ Fonts use font-display: swap
✅ CSS is code-split by route/chunk
✅ Gzip/Brotli compression enabled
✅ CSS file has content hash for caching
Examples
Production Build Script
// package.json
{
"scripts": {
"dev": "vite",
"build": "vite build",
"build:css": "tailwindcss -i ./src/input.css -o ./dist/output.css --minify",
"analyze": "npm run build && webpack-bundle-analyzer dist/stats.json"
}
}
Optimized Configuration
// tailwind.config.js
module.exports = {
content: {
files: [
'./src/**/*.{js,jsx,ts,tsx}',
'./components/**/*.{js,jsx,ts,tsx}',
],
// Only in dev: watch for changes
relative: process.env.NODE_ENV === 'development',
},
theme: {
extend: {
// Only extend what you need
colors: {
primary: 'rgb(var(--color-primary) / <alpha-value>)',
},
},
},
plugins: [
// Only include plugins you use
require('@tailwindcss/forms'),
],
// Disable unused variants
corePlugins: {
// Disable unused features
preflight: true,
// Only enable what you need
},
}
CDN vs Bundle Comparison
<!-- Bad: CDN (3.5MB+, not optimized) -->
<link href="https://cdn.jsdelivr.net/npm/tailwindcss@3/dist/tailwind.min.css" rel="stylesheet">
<!-- Good: Bundled & optimized (typically 5-20KB gzipped) -->
<link href="/dist/styles.css" rel="stylesheet">
Common Pitfalls
❌ Using CDN in Production
<!-- Never do this in production -->
<script src="https://cdn.tailwindcss.com"></script>
The CDN build is 3.5MB+ and includes all utilities. Always use a build process.
❌ Overly Broad Content Paths
// Bad: Scans everything including node_modules
content: ['./**/*.html']
// Good: Specific to your source files
content: ['./src/**/*.{html,js,jsx,ts,tsx}']
❌ Not Using Safelist for Dynamic Classes
// Bad: Class won't be included in build
const colors = ['red', 'blue', 'green']
<div className={`bg-${colors[index]}-500`} />
// Good: Use safelist or conditional classes
❌ Importing Full Tailwind in Components
// Bad: Imports all of Tailwind
import 'tailwindcss/tailwind.css'
// Good: Import only what you built
import './styles.css'
Anti-Patterns
❌ Don't Disable Purge in Production
// Bad: Never do this
module.exports = {
content: [], // Empty = no purging!
}
❌ Don't Use @apply Excessively
/* Bad: Defeating the purpose of utilities */
.btn { @apply px-4 py-2 bg-blue-500 text-white rounded; }
.card { @apply p-6 bg-white shadow-lg rounded-lg; }
.header { @apply flex items-center justify-between p-4; }
/* ...hundreds of components */
/* This negates Tailwind's optimization benefits */
❌ Don't Ignore Build Warnings
# Pay attention to warnings like:
# "The content option in your Tailwind CSS configuration is missing or empty"
# "No utility classes were detected in your source files"
Related Skills
- tailwind-configuration: Customizing Tailwind config and theme
- tailwind-utility-classes: Using Tailwind's utility classes effectively
- tailwind-responsive-design: Building responsive designs efficiently