Tailwind CSS kini mendapatkan lebih dari 50 juta unduhan npm mingguan — 12,5x lebih banyak dari Bootstrap — sementara CSS Modules tetap menjadi solusi styling bawaan untuk Next.js tanpa dependensi tambahan. Saya telah menggunakan keduanya di proyek produksi dan di portofolio saya sendiri (matthewswong.com), yang berjalan 100% pada Tailwind. Ini bukan perdebatan antara dua pilihan yang setara — untuk sebagian besar aplikasi web modern, verediknya jelas.
Tailwind CSS v4 (Januari 2025) adalah rilis monumental — build penuh hingga 5x lebih cepat dari v3, incremental build lebih dari 100x lebih cepat via mesin Oxide baru yang ditulis dalam Rust. Library ini melewati 50 juta unduhan npm mingguan dan melampaui Bootstrap sebagai framework CSS paling banyak diunduh. Sementara itu, CSS Modules bukan paket npm tunggal — ia dibangun ke dalam css-loader webpack dan diproses secara otomatis oleh Next.js.
Alasan Tailwind menang adalah kecepatan pengembangan, bukan performa. Menulis border border-gray-200 rounded-xl p-4 langsung di JSX lebih cepat daripada beralih ke file .module.css, menulis nama kelas, mengimpornya, dan menerapkannya. Untuk aplikasi React yang berfokus pada komponen, gesekan ini berlipat ganda di ratusan komponen. CSS Modules menukar sebagian kecepatan untuk pemisahan kekhawatiran — HTML Anda tetap bersih, style dikolokasikan per file komponen, dan Anda tidak perlu khawatir tentang benturan nama kelas secara global.
┌────────────────────────────┬────────────────────────────┐
│ Tailwind CSS │ CSS Modules │
├────────────────────────────┼────────────────────────────┤
│ 50M+ weekly npm downloads │ Built into css-loader │
│ v4: Oxide engine (Rust) │ No extra dependency │
│ Utility classes in JSX │ Scoped class names │
│ PurgeCSS built-in │ Explicit class creation │
│ shadcn/ui ecosystem │ Designer-friendly │
├────────────────────────────┼────────────────────────────┤
│ Button.tsx │ Button.tsx + Button.module │
│ className="px-4 py-2 │ import styles from ... │
│ bg-blue-500 text-white │ className={styles.button} │
│ rounded-lg hover:..." │ │
├────────────────────────────┼────────────────────────────┤
│ ✅ Fast iteration │ ✅ Clean HTML │
│ ✅ No naming decisions │ ✅ CSS-native power │
│ ✅ Design system built-in │ ✅ No class conflicts │
│ ❌ Verbose in JSX │ ❌ File context switching │
│ ❌ Learning curve │ ❌ More boilerplate │
└────────────────────────────┴────────────────────────────┘Dari membangun matthewswong.com sepenuhnya dengan Tailwind: gunakan utilitas cn() (dari clsx + tailwind-merge) untuk kelas kondisional. Tanpanya, Anda berakhir dengan string className penuh ternary yang menjadi tidak terbaca. Dengannya, logika kelas dinamis terbaca bersih: cn('rounded-xl p-4', isActive && 'bg-blue-500', disabled && 'opacity-50'). Satu pola ini menghilangkan 90% keluhan keterbacaan Tailwind.
Kisah performa Tailwind v4 kuat — mesin Oxide secara dramatis mengurangi waktu build. Untuk runtime, Tailwind menghasilkan hanya kelas CSS yang benar-benar Anda gunakan (via pemindaian konten), sehingga bundle produksi kecil. Aplikasi portofolio atau SaaS tipikal mengirimkan 10-30KB CSS dengan Tailwind. CSS Modules juga menghasilkan CSS minimal — hanya kelas dalam modul yang digunakan yang diekstraksi. Performa runtime kedua pendekatan pada dasarnya identik karena keduanya menghasilkan kelas CSS standar yang ditangani browser secara native.
// Install the cn utility
npm install clsx tailwind-merge
// lib/utils.ts
import { clsx, type ClassValue } from "clsx"
import { twMerge } from "tailwind-merge"
export function cn(...inputs: ClassValue[]) {
return twMerge(clsx(inputs))
}
// Usage in components
import { cn } from "@/lib/utils"
function Button({ variant, disabled, className }: ButtonProps) {
return (
<button
className={cn(
"px-4 py-2 rounded-lg font-medium transition-colors",
variant === "primary" && "bg-blue-500 text-white hover:bg-blue-600",
variant === "ghost" && "bg-transparent hover:bg-slate-100",
disabled && "opacity-50 cursor-not-allowed pointer-events-none",
className // allow consumer overrides
)}
>
{children}
</button>
)
}
// Tailwind v4: New CSS-first config (no more tailwind.config.js required)
// In your CSS file:
@import "tailwindcss";
@theme {
--color-brand: #3b82f6;
--font-sans: "Inter", sans-serif;
}CSS Modules bersinar dalam tiga skenario: (1) Library komponen yang Anda publikasikan ke npm — Anda tidak bisa mengharuskan konsumen menginstal Tailwind. (2) Tim dengan desainer yang menulis CSS — CSS Modules menghormati model mental desainer lebih baik dari utility classes. (3) Proyek dengan animasi kompleks atau pseudo-element yang membutuhkan kekuatan CSS penuh. Untuk proyek Next.js di mana tim semuanya pengembang dan kecepatan penting, Tailwind hampir selalu pilihan yang lebih baik.
Jika Anda mencoba mencampur Tailwind dan CSS Modules dalam proyek yang sama, Anda akan mengalami konflik urutan. Reset dan base style Tailwind bisa menimpa atau ditimpa oleh module CSS Anda tergantung urutan impor, yang non-deterministik dengan bundler. Pilih satu pendekatan per proyek dan tetap padanya. Satu pengecualian yang saya izinkan: gunakan CSS Modules untuk animasi @keyframe global (karena animasi arbitrary Tailwind menjadi verbose), tapi jaga semua styling komponen di Tailwind.
Saya menggunakan Tailwind CSS di setiap proyek baru, tanpa pengecualian. Keuntungan kecepatan nyata dan peningkatan DX signifikan — saya membuat prototipe komponen baru dalam setengah waktu dibandingkan CSS Modules. Di matthewswong.com, saya menggabungkan Tailwind dengan Framer Motion untuk animasi dan shadcn/ui untuk primitif komponen yang aksesibel.
Migrasi proyek CSS Modules yang ada ke Tailwind adalah tugas yang tidak sepele tapi bisa dikelola. Pendekatan yang saya rekomendasikan: instal Tailwind bersama CSS Modules (mereka bisa coexist sementara), konversi satu komponen sekaligus dimulai dari komponen daun terkecil, dan hapus file module setelah komponen dikonversi. Gunakan ekstensi VSCode Tailwind CSS IntelliSense dari hari pertama.
Tailwind CSS untuk proyek baru dengan tim yang berpusat pada pengembang. CSS Modules untuk library komponen yang dipublikasikan, tim campuran desainer-pengembang, atau ketika Anda butuh kontrol CSS penuh tanpa batasan. Keduanya menghasilkan performa runtime yang hampir identik — pilihan ini tentang pengalaman pengembang dan alur kerja tim, bukan kemampuan teknis. Jika Anda memulai aplikasi Next.js di 2025, gunakan Tailwind dengan shadcn/ui.