cn: The 30× Faster Tailwind Class MergerIf you've built a Tailwind CSS project of any real size, you know the drill. Your className props start as tidy strings and slowly mutate into conditional spaghetti:
className={`px-4 py-2 ${isActive ? 'bg-blue-500' : 'bg-gray-200'} ${size === 'lg' ? 'text-lg' : 'text-sm'} rounded-md`}
Then you discover clsx to clean up the conditionals. But then you hit the real wall: conflicting classes. You write px-4 in one place and px-6 in another, and Tailwind's stylesheet just applies whichever rule comes last in the CSS file—not the order you wrote them. That's where tailwind-merge comes in, resolving conflicts intelligently.
The standard stack—clsx + tailwind-merge—works. But it's slow, and it's heavy.
Enter cn, a new utility from the shadcn-ui organization. It replaces both libraries with a single function. Same API. Full parity. And it runs 30× faster.
Here are 10 reasons why cn deserves a spot in your next project.
The most compelling reason to switch? You don't have to learn anything new.
cn accepts the exact same inputs as clsx: strings, arrays, objects with boolean values, and nested combinations. If you've been using clsx + tailwind-merge, you already know how to use cn.
Here's what your code looks like today:
import { clsx } from 'clsx';
import { twMerge } from 'tailwind-merge';
function cn(...inputs) {
return twMerge(clsx(inputs));
}
Here's what it looks like with cn:
import { cn } from 'cn';
That's it. The function signature is identical. You pass the same arguments, you get the same output. The internal implementation is different—far faster—but your call sites don't change.
Key Takeaway: Migrating from
clsx+tailwind-mergetocnis a find-and-replace operation. No refactoring, no new patterns, no breaking changes.
The headline claim isn't marketing fluff. The benchmarks are real, and they're dramatic.
In controlled tests, cn processes class strings roughly 30× faster than the clsx + tailwind-merge combination. For a single call, the difference is measured in microseconds—negligible in isolation. But in a large application with hundreds of components rendering frequently, those microseconds compound.
Consider a data table rendering 500 rows, each row using five components with conditional classes. That's 2,500 cn calls per render. At 30× the speed, you're saving meaningful milliseconds on every single render cycle—which matters during rapid state updates, animations, or real-time data feeds.
Key Takeaway: The performance gain is most noticeable in component-heavy applications where class merging happens thousands of times per second.
clsx is tiny. tailwind-merge is not. Combined, they pull in a dependency tree that adds unnecessary weight to your node_modules.
cn ships with zero dependencies. No transitive packages, no hidden vulnerabilities, no version conflicts.
In terms of bundle size, cn comes in at under 2KB minified and gzipped. For comparison, tailwind-merge alone is around 6KB gzipped, and that's before you add clsx on top.
For client-side applications, every kilobyte affects load time, especially on slower connections. For library authors, smaller bundles mean consumers are more likely to adopt your package.
Key Takeaway:
cnreduces your dependency footprint and keeps your bundle lean—two wins with one swap.
The biggest fear when switching from tailwind-merge is losing conflict resolution capabilities. What about arbitrary values? Custom colors? Opacity modifiers? Responsive prefixes?
cn handles them all.
The library maintains full parity with tailwind-merge, meaning it resolves the same classes in the same order, with the same precedence rules. Later classes override earlier ones, regardless of where they appear in the string.
cn('px-2', 'px-4');
// Returns: 'px-4'
cn('bg-red-500 hover:bg-blue-500', 'bg-green-500');
// Returns: 'bg-green-500 hover:bg-blue-500'
cn('text-sm md:text-base', 'text-lg');
// Returns: 'text-lg md:text-base'
The last declaration wins—but only for the specific variant. Note in the second example that hover:bg-blue-500 survives because it's a different variant than the plain bg-green-500.
Key Takeaway:
cnmatchestailwind-merge's behavior exactly. If your current setup works,cnwill work the same way—just faster.
tailwind-merge and clsx are framework-agnostic, and so is cn. It doesn't care whether you're rendering with React, Vue, Svelte, Solid, or plain JavaScript.
React:
<div className={cn('flex', isMobile ? 'flex-col' : 'flex-row')}>
Vue:
<template>
<div :class="cn('p-4', active && 'bg-blue-500')">Content</div>
</template>
<script setup>
import { cn } from 'cn';
</script>
Vanilla JS:
const button = document.querySelector('.btn');
button.className = cn('btn', variant === 'primary' && 'btn-primary');
No framework-specific bindings, no assumptions about your rendering library, no SSR complications.
Key Takeaway: If your project uses Tailwind CSS,
cnworks. Period.
Installation takes seconds:
npm install cn
Or with your package manager of choice:
# pnpm
pnpm add cn
# yarn
yarn add cn
# bun
bun add cn
Once installed, import it wherever you need it. There's no configuration file, no plugin setup, no build step changes, and no Tailwind config modifications required.
If you're using a component library like shadcn/ui, you might already have a cn utility defined in your project. You can replace that local implementation with the package and delete your custom code.
Key Takeaway:
cnintegrates cleanly with existing Tailwind setups. You don't need to restructure anything to adopt it.
cn comes from the shadcn-ui organization—the same team behind shadcn/ui, one of the most popular component libraries in the React ecosystem. That backing lends immediate credibility and a built-in distribution channel.
The adoption numbers tell the story: within the first month of release, cn surpassed 10,000 weekly downloads on npm. That's rapid traction for a utility library, and it's accelerating.
Several open-source component libraries have already integrated cn internally, and it's being adopted in production applications across the React, Vue, and Svelte ecosystems.
Key Takeaway: When a utility comes from a trusted maintainer and gains traction quickly, it's a signal that the library solves a real problem well.
cn is fully open source under the MIT license. The source code is available on GitHub, and the project maintains 100% test coverage for its class conflict resolution logic.
That test coverage matters. Class merging is fiddly—there are edge cases with arbitrary values, negative margins, and complex variants. A library that tests those edge cases exhaustively is one you can trust in production.
The project also accepts community contributions. Bug reports, feature requests, and pull requests are reviewed and addressed by the maintainers. The roadmap is shaped by real-world usage, not a closed-door corporate agenda.
Key Takeaway: Transparent development and comprehensive testing make
cna safe bet for production use.
Tailwind CSS v4 introduced a new engine with significant internal changes. Some utilities built for v3 broke or required updates.
cn was designed with v4 compatibility from the start. It handles v4's new syntax, including the @theme directive and CSS-first configuration approach. But it also maintains backward compatibility with v3, so you can adopt cn now and upgrade Tailwind later without worrying about class resolution breaking.
The library's architecture is also designed to accommodate future Tailwind features. As new utilities and variants are added, cn can be updated to recognize them—without requiring a major version bump or API changes.
Key Takeaway: Choosing
cnpositions you well for Tailwind's evolution. You won't need to swap utilities again when v5 or v6 arrives.
The proof is in the usage. Developers who've integrated cn report tangible benefits:
"We integrated
cninto our component library and saw a noticeable improvement in rendering performance. Our dashboard renders hundreds of components on every keystroke, and the difference was immediately measurable." — Frontend engineer at a SaaS company"I replaced 40 lines of custom
cnlogic with a single import. My codebase is cleaner, and I deleted two dependencies from package.json." — Independent developer
The most common feedback isn't about speed—it's about simplicity. One import instead of two. One package to update instead of three (including tailwind-merge's dependencies). Less cognitive overhead when reasoning about class merging.
Key Takeaway: The real-world benefit goes beyond performance.
cnsimplifies your codebase and reduces dependency management overhead.
cn and why was it created?cn is a utility function for merging Tailwind CSS classes and resolving conflicts. It was created to replace the clsx + tailwind-merge combination with a single, faster library. The shadcn-ui organization developed it after identifying performance bottlenecks in large applications using the traditional stack.
cn achieve 30× faster performance?tailwind-merge relies heavily on regex-based parsing to identify and categorize classes. cn uses a custom algorithm that avoids regex overhead, processing class strings more directly. This architectural difference accounts for the dramatic speed improvement.
cn a drop-in replacement for clsx and tailwind-merge?Yes. It accepts the same input types (strings, arrays, objects) and produces the same output. You can replace your existing cn implementation without changing any call sites.
cn support all Tailwind CSS features?Yes. It supports Tailwind v3 and v4, including custom configurations, arbitrary values, all standard variants (hover, focus, responsive prefixes, etc.), and group/peer variants.
cn be used with frameworks other than React?Absolutely. It's framework-agnostic and works with Vue, Svelte, Solid, Angular, or vanilla JavaScript.
cn over clsx + tailwind-merge?Three primary benefits: 30× faster execution, zero dependencies, and a smaller bundle size (under 2KB gzipped vs. roughly 7KB for the combined alternatives).
cn production-ready?Yes. It has 100% test coverage for conflict resolution, is maintained by the shadcn-ui organization, and is already used in production applications and open-source libraries.
cn?npm install cn
That's it. No additional configuration needed.
cn work with Tailwind CSS v4?Yes, cn was built with v4 compatibility in mind and also maintains full support for v3.
cn?The library is relatively new, so the ecosystem of community plugins and extensions is still growing. However, for standard Tailwind usage, there are no known limitations compared to clsx + tailwind-merge.
The clsx + tailwind-merge combination served the Tailwind community well, but it has limits. cn addresses those limits directly:
If you're building a serious Tailwind project, cn is worth a serious look. The migration is trivial, the performance gains are measurable, and the maintenance benefits are immediate.
Ready to supercharge your Tailwind CSS workflow? Install cn today and experience the 30× speed boost for yourself. Visit the GitHub repository for documentation and examples.