SCSS vs Tailwind: My Honest Take After Years of Both
3 min read
I wrote SCSS professionally for years on enterprise commerce projects — SAP Spartacus storefronts where the design system arrives as a specification document — and Tailwind on newer SaaS and healthcare products. I've also held the standard opinions in the standard order: "utility classes are inline styles with extra steps," followed some months later by quietly shipping everything in Tailwind. Here's the comparison I'd give a team choosing today.
The assumption I had to unlearn
My objection to Tailwind was aesthetic: class="flex items-center gap-3 rounded-lg border" looks like markup soup next to a tidy .product-card. What I missed is that
the tidy class name was hiding the actual cost — every .product-card is a new
abstraction someone must name, place in a file, keep in sync with the markup, and
eventually be afraid to delete. Tailwind's verbosity is visible cost; SCSS's
indirection is deferred cost. Deferred costs compound.
SCSS: the strength and the limitation
The strength is expressive power under a real design language. On Spartacus work, SCSS earned its keep daily: theming an entire storefront through variable overrides, mixins encapsulating brand-specific patterns, and the cascade deliberately used to restyle a third-party component library from outside. When you must impose your design onto markup you don't own — exactly the enterprise-commerce situation — SCSS is the right tool, and Tailwind mostly isn't in the running.
The limitation is entropy at team scale. Every SCSS codebase I've inherited had the
same archaeology: 40% of selectors no longer matched anything, specificity wars fought
with !important, and seven slightly different gray-border-card implementations because
finding the existing one was harder than writing another. SCSS gives a team unlimited
freedom and no guardrails; over years, that freedom is the technical debt.
Tailwind: the strength and the limitation
The strength is constraint plus locality. Tailwind's spacing/color scale is a design-token system you don't have to build (tokens explained here) — designers and developers end up speaking the same scale. And because styles live in the markup, deleting a component deletes its styles; there is no orphaned CSS, ever. On the healthcare product, new screens compose existing utilities with near-zero style review — consistency is the default, not an achievement.
The limitation is repetition without discipline. Utility strings duplicated across
twelve files are real; the fix is componentization (extract a Card component, not a
.card class). Teams that won't invest in a component layer end up with the same
inconsistency SCSS produces, just more visibly. Tailwind also has a genuine reading
curve — the first two weeks are slower, and long class strings never stop offending
people who value clean markup.
My actual rule for choosing
- Fast-moving product team building its own UI in a component framework (React, Vue, Angular with components) → Tailwind. The constraint system and deletability compound in your favor.
- Large legacy design system, or styling markup you don't fully control (CMS output, third-party libraries, enterprise storefronts) → SCSS. You need the cascade, selectors, and theming power.
- Component library published for others → lean SCSS/vanilla with design tokens; don't impose your utility framework on consumers.
What large legacy codebases taught me
The deciding insight came from maintenance, not greenfield work. Styling systems are judged in year three, not week one — and in year three, the Tailwind codebases I work in are boringly consistent while the SCSS ones require archaeology. But the causation isn't the tool: it's that Tailwind makes the undisciplined path harder and SCSS makes it easier. A disciplined team with design tokens, code review, and a component culture produces maintainable CSS in either. Choose based on which failure mode your team is more likely to fall into — that's the honest version of this debate.