tailwind-merge is a package that merges a string of tailwind utilities and merges them from left to right in specificity. This means that bg-red-500 bg-blue-500 would produce bg-blue-500. This works effectively when users want to override the classes by providing their own. This does have a runtime cost, which means everytime a user applies a class themselves tailwind-merge will have to figure out wether or not it should be applied based on the already applied classes.
tailwind-merge is 7.40 KB Minified + GZipped.
base: is a way of specifiying styles with a lower specificity than "normal" styles using a combination of CSS Layering and Tailwind's new @custom-variant rule. This was made possible by the recent Tailwind V4 update which allows you to create custom variants.
This is what the base: utility looks like:
@custom-variant base {
@layer base {
@slot;
}
}It enables to write Tailwind classes like base:bg-red-500.
Let's say we have the following classes: bg-red-500 bg-blue-500, will it be red or blue?
Because the order tailwind compiles classes in is not reliable, either red or blue being the one that is finally applied by the browser, hence tailwinds warning.
This is ofcourse not something we as library authors want. If we provide a red background, and the user wants a blue background, the user's choice should always override ours.
Now let's use the previously mentioned base: utility and apply it like so: base:bg-red-500 bg-blue-500. This is what the new compiled output looks like:
Notice how the bg-red-500 is now wrapped in @layer base meaning it has a lower specificity and we can predict with confidence that the bg-blue-500 will be applied. This is exactly the behaviour we're after.
- Tailwind's playground without anything written is
1.08KB. - Tailwind's playground with base variant only remains
1.08KB.
Now let's introduce some styles that utilize the new base: variant.
Here is a table of components and the bundle size in tailwind they cause:
| Component | Bundle Size | Playground |
|---|---|---|
| Accordion | 0.21 KB |
https://play.tailwindcss.com/ubpY3LSOuq |
| AppBar | 0.24 KB |
https://play.tailwindcss.com/sXKUXWlyrh |
| FileUpload | 0.27 KB |
https://play.tailwindcss.com/vw51cbLKFB |
Out of this table we can conclude that on average a component might introduce around 0.25 KB worth of CSS, worth noting is that if a user consumes a component twice, the styling will only be included once, because Tailwind only compiles those styles once and if they're duplicate they'll be reused. So this means even if we were to have 30 components and someone would use every component in their app (which is extremely unlikely) we would only ship 7.5 KB. Which is very acceptable without any runtime cost.
Because tailwind-merge adds ~7 KB regardless of how much we use it and components only gradually increase bundle size by small amounts I would strongly lean towards using the base: approach. It also saves a dependency which is good for many reasons.

