Comparison
Tailwind or CSS Modules? Velocity against isolation
The verdict
For a new application, pick Tailwind v4. It is the default in shadcn/ui, in most framework starters, and in essentially every AI code generator, its Rust-based Oxide engine is, by Tailwind's own benchmark on its Catalyst project, a full build cut from 378 ms to 100 ms with incremental builds that add no new CSS dropping from 35 ms to 192 microseconds, and production CSS typically lands between 5 and 20 KB. Pick CSS Modules when you are publishing a component library that other teams install, when the codebase is a large existing SCSS estate you are migrating incrementally, or when strict per-component isolation is a design system requirement rather than a preference. This site is built with Tailwind v4, so treat the verdict as disclosed bias plus a real reason.
The gap between these two is the narrowest it has ever been. Tailwind v4 moved configuration into CSS with @theme, replaced the PostCSS plugin, JIT compiler and content scanner with one Rust engine, and reports full rebuilds 3.5 to 10 times faster with incremental rebuilds over 100 times faster. CSS Modules did not change, because it is a bundler feature rather than a product - and that stability is exactly its pitch.

When each approach is the right call
Choose Tailwind when
- You are building application UI where components are consumed inside your own codebase, not published to strangers.
- The team is small and nobody wants to own a CSS architecture, a naming convention, or a spacing scale.
- You want shadcn/ui or a Tailwind template as a starting point rather than building primitives from zero.
- Dead style elimination should be automatic. Delete the component, and its CSS stops being emitted.
- You use AI assistance heavily, where utility classes in the markup are what models produce most reliably.
Choose CSS Modules when
- You publish a component library to npm and cannot require consumers to configure a styling framework.
- The design system is strict and enforced, and inline utilities would let anyone bypass it in a hurry.
- The styling is genuinely complex: multi-step keyframes, deep selector logic, print stylesheets, heavy container queries.
- You are migrating a large SCSS codebase and want to move file by file with no framework rewrite in between.
- Your team has real CSS depth and treats readable markup as a maintenance asset, which is a defensible position.
The failure modes on each side
Tailwind fails when a team treats @apply as the escape hatch. Pulling utility strings into named CSS classes recreates every problem Tailwind was meant to remove - a second naming system, specificity questions, and dead rules that nothing eliminates - while keeping the framework dependency. The correct move is to extract a component, not a class. If a button appears in forty places, make a Button component; do not make a .btn rule out of applied utilities.
CSS Modules fails on drift. Without an enforced token layer, three developers produce three spacing scales and four blues within a quarter, and none of it is visible in review because each file looks reasonable on its own. Custom properties solve this, but only if somebody owns them and the linter enforces them. Teams that succeed with CSS Modules invariably have a person or a document doing the job Tailwind's config does automatically.
The second Tailwind cost is human rather than technical. A responsive, dark-mode, hover-state element can carry twenty-plus classes, and that line is genuinely harder to read than the equivalent CSS block. Multi-line class formatting and the official Prettier plugin for class sorting help considerably, and both are worth adopting on day one rather than after the first argument in a pull request.
Worth saying plainly: this is a reversible decision, unlike most of the choices on this site. Converting a component from CSS Modules to Tailwind or back is a contained, mechanical change with no data migration, no downtime, and no ecosystem cost. Do not spend a week deciding. Pick the one your team can move fastest in, ship, and revisit if it hurts. The Tailwind documentation is at tailwindcss.com; CSS Modules is documented by whichever bundler you already use.
Where this fits in a full stack
The CSS and UI layer covers the component libraries built on each approach, plus the CSS-in-JS options this comparison left out. For the utility names and responsive prefixes themselves, the Tailwind CSS cheatsheet is the faster reference.
Styling is one layer of a build. The static and content site stack guide shows how it fits with a framework, a content source and a host. Other close calls are in the comparisons index.