_A honest discussion about the trade-offs nobody
Introduction
After 5 years of using Tailwind CSS in production, I’ve learned some hard lessons about utility-first CSS at scale. This isn’t another “Tailwind bad” rant — it’s an honest conversation about when this popular framework starts showing its limitations.
Disclaimer: I don’t have exact metrics to share (NDAs exist), but I’ll walk you through the real patterns and problems we encountered.
The Good: Why We Chose Tailwind
Let’s start with credit where it’s due. Tailwind CSS delivers on many promises:
- Rapid prototyping — Building UIs has never been faster
- No context switching — Stay in your HTML/JSX files
- Consistent spacing — The design system is built-in
- Small learning curve — New developers can contribute immediately
For the first few months, it felt revolutionary.
The Reality Check: When Scale Hits
1. The Readability Problem
Here’s what our components started looking like:
// A real card component from our codebase
<article className="relative flex flex-col min-w-0 rounded-lg break-words border border-gray-200 bg-white shadow-sm dark:border-gray-700 dark:bg-gray-800 md:flex-row md:items-center md:justify-between hover:shadow-lg transition-shadow duration-200">
<div className="flex-1 p-4 md:p-6 lg:p-8">
<h2 className="text-lg md:text-xl lg:text-2xl font-semibold text-gray-900 dark:text-white mb-2">
{title}
</h2>
<p className="text-sm md:textbase text-gray-600 dark:text-gray-300 line-clamp-3">
{description}
</p>
</div>
</article>
The problem?
- Can you tell what this component does at a glance?
- How would you modify just the desktop layout?
- Where does the component styling end and utility classes begin?
2. The Maintenance Challenge
Consider this scenario we faced last fewmonths:
Design team: “We need to update all card shadows to be more subtle”
With Tailwind: Search for shadow-sm, shadow-lg, hover:shadow-xl across:
- Components
- Templates
- Random utility combinations
- Third-party components we customized
With CSS Modules: Update one variable:
:root {
--card-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);
}
3. The Bundle Size Discussion
While Tailwind’s PurgeCSS is impressive, here’s what people don’t discuss:
// What your HTML looks like
<div className="p-4 md:p-6 lg:p-8 xl:p-10 2xl:p-12">
// What CSS gets generated (simplified)
.p-4 { padding: 1rem; }
.md\:p-6 { padding: 1.5rem; }
.lg\:p-8 { padding: 2rem; }
.xl\:p-10 { padding: 2.5rem; }
.2xl\:p-12 { padding: 3rem; }
Compare to modern CSS:
.container {
padding: clamp(1rem, 4vw, 3rem);
}
One line vs five classes. Multiply this by every responsive property in your app.
The Patterns That Hurt Us
Anti-Pattern 1: The Copy-Paste Culture
New developers would copy this:
<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded">
Instead of using:
<Button variant="primary">
Result: Inconsistent button implementations everywhere
Anti-Pattern 2: The Component Sprawl
// What we ended up with across different files
<div className="bg-white p-6 rounded-lg shadow-md">
<div className="bg-white p-4 rounded shadow-sm">
<div className="bg-white p-8 rounded-xl shadow-lg">
Result: Three slightly different “card” components that should have been one reusable <Card> component.
Anti-Pattern 3: The Responsive Madness
<div className="text-sm md:text-base lg:text-lg xl:text-xl 2xl:text-2xl p-2 md:p-4 lg:p-6 xl:p-8 2xl:p-10 m-1 md:m-2 lg:m-3 xl:m-4 2xl:m-5">
Compare this to modern CSS
.responsive-text {
font-size: clamp(0.875rem, 2.5vw, 1.5rem);
padding: clamp(0.5rem, 4vw, 2.5rem);
margin: clamp(0.25rem, 1vw, 1.25rem);
}
The Real Numbers: What UK Developers Are Saying
------------------------to---------------------
Based on recent survey data, the UK was among the top three countries participating in developer surveys, alongside the USA and Germany State of CSS 2024 Survey Now Open — WP Tavern. Here’s what the data reveals:
Usage Reality Check: While 75% usage seems impressive, only 50% of survey respondents actually answered the Tailwind question.
This means real usage is closer to 37.5% of all developers 🔍 Going through the “State of CSS” results… • Josh W. Comeau — significant, but not the overwhelming majority some claim.
The Maintenance Problem is Real: As one developer put it:
“I really tried to like Tailwind. And I understand what it does and its benefits. But ease of code readability, to me anyway, is #1. I am not used to having my HTML/JSX/whatever filled to the brim with a million classes. It’s unbelievably messy.”
When Tailwind Actually Works Well
Let’s be fair — Tailwind isn’t always the wrong choice:
- Rapid prototyping — For hackathons and proof-of-concepts
- Small teams with limited CSS knowledge
- Projects with simple design systems
- Marketing sites with minimal maintenance needs
The key insight: It’s perfect for projects compatible with uncomplicated CSS and low maintenance, and it’s ideal for front-end teams with little knowledge of CSS or limited resources allocated for CSS architecture.
My solution: A Hybrid Approach
After few years of pure Tailwind, here’s what we’re moving towards:
Component-First Architecture
// Instead of this Tailwind mess
<button className="bg-blue-500 hover:bg-blue-700 text-white font-bold py-2 px-4 rounded focus:outline-none focus:shadow-outline">
// We use this <Button variant="primary">Submit</Button>
CSS Custom Properties for Theming
:root { --color-primary: #3b82f6;
--spacing-card: clamp(1rem, 4vw, 2rem);
--shadow-card: 0 4px 6px -1px rgba(0, 0, 0, 0.1);
}
Modern CSS Features
.container {
container-type: inline-size;
padding: clamp(1rem, 5vw, 3rem);
}
.card { padding: var(--spacing-card);
box-shadow: var(--shadow-card);
}
@container (min-width: 768px) {
.card-content {
display: grid; grid-template-columns: 1fr 2fr; gap: 2rem;
}
}
The Final Verdict
Tailwind CSS isn’t inherently bad — it’s a tool that works brilliantly for specific use cases. However, the scenario where “what once felt like a productivity boost now feels like technical debt” is all too common when developers adopt Tailwind without established patterns for large-scale implementations Best Practices for Using Tailwind CSS in Large Projects — Wisp CMS.
The hard truth? For large-scale projects, traditional CSS architecture often provides better long-term maintainability, performance, and developer experience.
Before choosing Tailwind, ask yourself:
- Will this project need significant design updates?
- Do we have senior CSS developers on the team?
- Are we building a design system that will be used across multiple projects?
- Do we need fine-grained control over our styles?
If you answered “yes” to any of these, consider modern CSS approaches instead.
Remember: The goal isn’t to use the trendiest tool — it’s to build maintainable, performant websites that serve your users well.
What’s been your experience with Tailwind at scale? Have you faced similar challenges, or found solutions that work? I’d love to hear your thoughts in the comments below.

Top comments (10)
I think this misses one key point about Tailwind in modern component-based frameworks (React/Angular/etc).
The "loss of semantic meaning" only exists if you stop at utility classes. In a proper setup, semantics move up into components. We don’t need
<button class="primary-submit">— we build<PrimarySubmitButton />, and the Tailwind utilities live inside it.Prototype fast → extract to components → reuse.
If Tailwind is leaking all over pages, that’s not a Tailwind problem, it’s an architectural one.
And... you just created a leaky abstraction.
I see what you mean about leaky abstractions, but in this case the abstraction is intentional and controlled. encapsulates all the Tailwind classes, so the parent page doesn’t need to know anything about the styling details.
If the component is well-designed, any “leakage” is internal, not exposed—Tailwind stays an implementation detail. The leak you mention usually happens when utilities are scattered across pages, not when they’re wrapped in semantic components.
Using frameworks like MUI I've found them to be really leaky abstractions. "Oh, I want this to work slightly differently, oh, its code is encapsulated and I can't change how it works for this one thing I need."
I prefer to just add the class myself to the HTML. Old school, but now I have full control.
But, yes, if you control the component then it isn't as big of a deal. Granted, if you don't expose the internals and someone tries to update the anchor element with an attribute and then becomes confused as to why it isn't working... true story, not me but a coworker.
In my previous role we definitely had a mixed approach of tailwind and custom classes. We usually used tailwind classes for basic layout (grid, flex, responsive columns etc) and custom classes for everything else. I think also using a CSS preprocessor like Sass really helps to keep styles reusable and scoped cleanly which makes the system more scalable.
I also wonder how far Tailwind’s own features could help mitigate the copy/paste inconsistency problem. Extracting classes using
@applyin v3 or@layerin v4 could centralize common patterns like buttons/cards so you’re not repeating utilities everywhere. It feels like Tailwind can work at scale, but only if there’s intentional architecture on top of it.I'll take this a step further and boldly say that Tailwind is inherently bad. Even the use cases you list are vastly debatable.
Rapid prototyping
It works, but other alternatives don't force you to raise a complex build system just for make it compile. It also doesn't provide pre-made customizable components like Bootstrap gives you, so you have to provide your own -- that works well with Tailwind, of course.
Small teams with limited CSS knowledge
In no case Tailwind saves you to actually know CSS. It may give you the impression, but it fades once you start struggling with complex layouts and less-than-trivial values. And maybe with the inevitable cascade problems once someone discovers the square bracket syntax.
Projects with simple design systems
Then probably Tailwind is overkill. Because Tailwind aims to completely replace CSS files, so tends to be equivalent.
Marketing sites with minimal maintenance needs
If I had a medal every time someone said a project "needed minimal maintainance" only to discover that maintainance actually costed much more effort than anticipated, I'd be forced on my knees...
The only good thing I can find in Tailwind is its default design token, which is good - but, after all, not better than less pervasive alternatives.
You're right. But it's even worse than this.
I've been a professional software developer since 10 years before the first web browser. I've seen tech change over the years. The problem exists beyond Tailwind and CSS to frameworks and tools.
About 10-15 years ago, web development grew impatient with HTML and CSS and decided to code their own version with frameworks and CSS libraries. We lost our way. TailwindCSS is just one example. I've loved a LOT of frameworks in the last 15 years but after taking a look at NueJS, I now realize how derailed we've been. While we've been reinventing everything, often poorly, HTML, CSS and JS have been evolving.
Take a look at this short page for the short summary of what's wrong with web development in 2025. (You don't need to love the Nue solution to recognize the significant problems it is trying to solve.) I can't believe I didn't see these problems sooner. I felt them, but I didn't really clue in so clearly until now. To me, your article is another example of someone zooming out and seeing the problem(s), or at least recognizing the significant clues that are right there in front of us. Kudos for posting it and getting the discussion going.
Great observation! I had the same problem with one of my projects, I choose to use TailwindCSS and I couldn't change some of the issues regarding the usability of some forms. It was a nightmare. In the second version of the application I used HTML5 boiler template. My problems are gone now.
I worked a bit more at the beginning but the usability works smooth and I can maintain it easily.
Great observation! I feel the same – Tailwind is amazing for prototyping, but not necessarily for large projects. And who loved it the most? Backend devs who occasionally had to do something on the frontend 😅
I think it is more of a frontend FOMO thing like SPA or micro frontends.
People see it used in one situation and then they want to use it everywhere.
I still don't understand why people are drawn to a utility classes only framework. Utility classes are not bad but this is the equivalent of using a, b and c to name your variables. You don't create context, it is easy to make mistakes, and you are copying things all over the code.
Bootstrap has flaws, but when CSS got better they incorporated the new features. I see that that less with Tailwind. It looks like they are more concerned with improving the utility classes.
With every tool people create you have to ask yourself, do I need this for my application.