Is Tailwind actually slow?
Source: Dev.to
Tailwind managed to conquer the hearts of many developers and at the same time become the most despised CSS framework for many others. People love and hate it for a variety of reasons, but today I want to talk about Tailwind CSS performance. Some skeptical developers believe that Tailwind can negatively affect loading and rendering times. But does it?
In this article I address the following allegations:
- “Tailwind may negatively affect the rendering time.” – Too many atomic CSS classes may cause additional CPU load.
- “Tailwind may negatively affect the loading time.” – It is not efficient lazy‑loading‑wise.
- “Tailwind may negatively affect website cache.”
- The size of generated HTML files is usually larger with Tailwind.
- Generated CSS may reset its cache more often compared with BEM or CSS Modules.
Quick remark: Some problems attributed to Tailwind are actually problems of the atomic styling approach. Tailwind allows you to create components (non‑atomic styling). However, many developers use Tailwind solely for atomic styling, which is the focus of this discussion.
Tailwind may negatively affect the rendering time
Why do some developers believe this?
The common understanding is that the more CSS declarations a page has, the slower the browser may process them. In the atomic styling approach, most declarations contain only 1–3 CSS rules, so developers often use a relatively large number of classes.
For example, to “center a div” using Flexbox you need three Tailwind classes:
<!-- Example placeholder -->
<div class="flex items-center justify-center">
…
</div>
Each class generates a separate style declaration. In a non‑atomic approach (e.g., CSS Modules or BEM) you could combine those rules into a single selector.
Benchmark
I set up a benchmark to test the claim.
| Tailwind | CSS Modules | |
|---|---|---|
| Components | ~5 000 | ~5 000 |
| DOM nodes total | ~20 000 | ~20 000 |
| CSS file size | 1.4 MB | 1.4 MB |
| Style declarations | 35 K | 10 K |
Sample components
// Tailwind component (class names differ per component)
<header className="flex gap-[0.0px]">
{/* … */}
<h2>Heading</h2>
</header>
// CSS Modules component (unique class name per component)
<header className={styles.header}>
{/* … */}
<h2>Heading 0</h2>
</header>
/* CSS Modules generated rules (repeat Tailwind styling) */
.egTxNhojHMGgAu4egvUQ { /* … */ }
.egTxNhojHMGgAu4egvUQ > header { /* … */ }
Results (parsing/rendering only, after download)

| Browser | Tailwind | CSS Modules | Difference |
|---|---|---|---|
| Chrome | 169 ms | 121 ms | +28 % |
| Safari | 406 ms | 272 ms | +33 % |
| Firefox | 114 ms | 82 ms | +25 % |
The larger number of style declarations does increase rendering time.
Does HTML size matter?
Tailwind’s class lists are longer, resulting in larger HTML (≈ 1.1 MB vs. 0.4 MB). To isolate the effect, I padded the CSS Modules class names to match Tailwind’s HTML size:
<header className="flex gap-[0.0px]">
…
</header>
Even with equal HTML size, the CSS Modules file grew to 2.7 MB (vs. 1.4 MB for Tailwind), yet Tailwind remained faster. The length of class names adds only a few milliseconds; the dominant factor is the number of CSS declarations.
Takeaways
- The atomic approach itself isn’t the problem; the sheer number of unique declarations is.
- Use Tailwind’s utility classes for common patterns (e.g.,
mt-1,mt-2,mt-4). - Avoid generating many arbitrary values (
mt-[7px],[&>header]:flex) unless necessary; they create unique selectors that bloat the stylesheet and hurt performance.
📌 Using Tailwind and the atomic approach may affect rendering performance negatively, but only when you misuse it by creating many unique, arbitrary class names.
Tailwind may negatively affect the loading time
Tailwind does not rely on lazy loading. If a page is lazy‑loaded and its styles are declared with Tailwind, all those styles are included in the initially loaded CSS file. Consequently, if you have 100 lazily loaded pages, the styles for all 100 pages are bundled into the initial CSS payload, increasing the amount of CSS the browser must download before rendering.
To mitigate this, consider:
- Purging unused utilities (e.g., using Tailwind’s
purge/contentoption) so only the classes actually used in the initial view are shipped. - Splitting CSS into per‑route bundles with tools like webpack, Vite, or Next.js’s built‑in CSS code‑splitting.
- Using component extraction (
@applyor custom components) to reduce the number of unique utility classes.
By carefully configuring Tailwind’s build pipeline, you can keep the initial CSS payload small and avoid unnecessary loading overhead.