cnfast: a drop-in cn replacement whose own README points elsewhere
25× faster drop-in replacement for `cn`
At a glance
- What is it?
- cnfast swaps tailwind-merge plus clsx for a single package with the same API. Its README now tells you to use shadcn's cn instead, and that note is the most important thing about the project.
- Who is it for?
- cnfast is worth adopting only if you already depend on it or need the exact cnfast API surface today, and you accept that the README states it will no longer be maintained in favor of shadcn's cn. If you are starting fresh, install shadcn's cn instead and skip the migration.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 16 days ago.
- What is it written in?
- Mainly TypeScript, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on September 17, 2026, and from our analysis. They are not legal advice.
DEEP OPEN-SOURCE ANALYSIS
What cnfast replaces, and the note at the top of its README
Tailwind projects usually build a `cn` helper out of two packages: `clsx` to flatten conditional class values, and `tailwind-merge` to resolve conflicts when later classes should win. cnfast ships that combined helper as one package. Its README shows the swap as a one-line change to the helper file and states that cnfast exports `clsx`, `twMerge`, and `twJoin` as well, so existing call sites that import those names from the old packages have a path forward.
The same README opens with a note that changes how the project should be read. It points to `cn` by shadcn, describes that package as even faster, and says cnfast will no longer be maintained in favor of it, recommending the other package instead. A library whose own documentation redirects readers away from it is not a normal adoption decision. The last push to the repository was on 2026-09-01, so the code is recent, but recency of commits is not the same thing as a commitment to future maintenance, and the README explicitly withdraws that commitment.
The performance claim is specific: 25x faster than `tailwind-merge` plus `clsx` across 58 real-world repositories, with byte-identical output. That number comes from the project's own benchmark page at cn.aidenybai.com. It is a claim about relative speed on a fixed corpus, not a statement about what any individual application will see, and the corpus is not described in the README.
How the helper resolves conflicting Tailwind classes
The README's example is the clearest description of the data flow:
import { cn } from "cnfast";
cn("px-2 py-1", isActive && "px-4", { "text-red-500": hasError });
// "py-1 px-4 text-red-500"Inputs arrive in mixed forms: plain strings, falsy values from short-circuit expressions, and object maps whose keys are class names and whose values decide inclusion. The falsy `isActive` case is dropped rather than stringified. The object form contributes `text-red-500` only when `hasError` is truthy. What comes back is a single class string.
The interesting part is the ordering. `px-2` appears before `px-4`, and the output keeps `px-4` while removing `px-2`, because in Tailwind the later declaration is the one that should apply. That conflict resolution is what `tailwind-merge` does and what a plain `clsx` call does not: `clsx` would return both padding classes and leave the browser to sort it out by stylesheet order, which is exactly the bug the merged helper exists to prevent. cnfast's claim is that it produces the same resolved string as the two-package combination, so the output is not merely similar but identical, which is what makes the swap safe to attempt without touching call sites.
The repository is a pnpm workspace. The root `package.json` is private and named `@cnfast/monorepo`, with the publishable package living under `packages/`. Benchmarking is wired as separate scripts (`bench`, `bench:report`, `bench:setup`) and there is a dedicated `@cnfast/benchmark` package, so the 25x figure is produced by tooling in the repository rather than asserted without support. The README does not explain how the 58 repositories were selected or what the benchmark measures.
Installing cnfast and migrating an existing project
Installation is a single npm command. The package is published as `cnfast` on npm.
npm install cnfastFor a new helper file, the README's usage section shows the before and after directly. The before version imports `clsx` and `tailwind-merge` and composes them; the after version is one re-export.
// before
import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";
export const cn = (...inputs: ClassValue[]) => twMerge(clsx(inputs));
// after
export { cn } from "cnfast";Existing projects have a codemod. The README gives this command for migrating a `clsx`, `classnames`, or `tailwind-merge` project:
npx cnfast migrateRun it on a branch and read the diff before merging. The README does not document rollback, does not list which files the codemod touches, and does not say whether it rewrites import statements across the codebase or only the helper module. On a shadcn/ui project there is a second path, which the README says rewrites `lib/utils.ts` to re-export cnfast and installs the package:
npx shadcn@latest add aidenybai/cnfast/cnAfter either path, the first real check is a component that passes conflicting utilities. Render something with both `px-2` and a conditional `px-4` and confirm the class string matches what the old helper produced. Byte-identical output is the property the migration depends on, so a diff in rendered markup is the signal that the swap is not transparent in your code.
The maintenance position is the main limitation
The README's deprecation note is not a hedge or a roadmap item. It states the project will no longer be maintained in favor of shadcn's `cn` and recommends that package instead. That is a direct statement from the maintainer, and it should govern the decision more than any benchmark number.
What that means in practice: bug reports against class-merge edge cases may not be fixed, new Tailwind utility syntax may not be added to the conflict-resolution tables, and a future Tailwind release could change the set of classes that need merging without a corresponding change here. The README does not describe a support window, a final version, or a date after which the package stops receiving updates. The most recent release is `cnfast@0.2.0` from 2026-09-01, and the repository's last push is the same day, so nothing indicates an abrupt stop, but the stated intent is enough to make the package a poor default for new work.
There is a second limitation that applies even while the package is current. The 25x figure is a benchmark result against `tailwind-merge` plus `clsx` on a fixed corpus of 58 repositories. Class merging is typically a small share of render time in an application, so a large relative speedup in the helper does not translate into a large absolute improvement in a page. If the goal is a faster application, the helper is unlikely to be where the time is going. cnfast is a reasonable answer to a narrow question about helper overhead and a weak answer to a broad question about frontend performance.
shadcn's cn is the alternative the README names
The README points to `cn` from shadcn as the replacement, describing it as even faster. The difference is not in the API, since both expose a `cn` helper with the same calling convention and cnfast's own migration path is designed to make the two interchangeable. The difference is in who maintains it and what that implies.
Choosing shadcn's `cn` means the helper is maintained alongside the component registry that most Tailwind projects using this pattern already depend on. Choosing cnfast means a smaller, single-purpose package with a stated end date for maintenance. For a project that already uses shadcn/ui components, the registry command in cnfast's README exists precisely because the two live in the same ecosystem, which makes the switch between them low-friction in both directions.
The trade-off is that cnfast's benchmark claim is the reason to pick it, and that claim is measured against `tailwind-merge` plus `clsx`, not against shadcn's `cn`. The README does not offer a comparison between cnfast and the package it recommends. So a reader who wants the fastest helper cannot settle the question from this repository's documentation alone.
Licence, upgrade cost and what the repository does not say
cnfast is MIT licensed, and the root `package.json` marks the monorepo private while the published package carries the licence file at the repository root. MIT permits use in closed-source projects and modification, provided the copyright notice and permission notice are retained. That is a general description of the licence text, not legal advice; check the LICENSE file and your own obligations.
The upgrade cost is dominated by the deprecation note rather than by version churn. The package is at 0.2.0, so the API has not had time to accumulate breaking changes, and there is a changesets setup in the repository (`.changeset/`, `@changesets/cli`, a `release` script running `changeset publish`) that suggests versioning is handled deliberately. But a package that will not be maintained has an upgrade cost that is not measured in releases: it is the cost of migrating off it later, which is exactly the migration the README already documents in the other direction.
Several things a reader would want are absent. The README does not document the benchmark methodology, how the 58 repositories were chosen, or how to reproduce the 25x result locally, beyond the existence of `bench`, `bench:setup` and `bench:report` scripts in the monorepo. It does not state a supported Tailwind version, a supported Node version for consumers (the root `engines` field requires Node 22 or later for development, which is not necessarily the same constraint for the published package), or a browser support policy. It does not describe what happens when a class it does not recognize is passed in, which is the failure mode most likely to bite a real application when Tailwind adds new utilities.
Editorial conclusion
cnfast is worth adopting only if you already depend on it or need the exact cnfast API surface today, and you accept that the README states it will no longer be maintained in favor of shadcn's cn. If you are starting fresh, install shadcn's cn instead and skip the migration. Before committing, run npx cnfast migrate on a branch and check the diff in lib/utils.ts, because the codemod rewrites import sites rather than only the helper.
Frequently asked questions
What is cnfast?
It is a single-package replacement for the combination of `tailwind-merge` and `clsx`, exposing the same `cn` helper plus `clsx`, `twMerge` and `twJoin`. The README claims it runs 25x faster than the two-package setup across 58 real-world repositories with byte-identical output.
How do I install cnfast?
Run `npm install cnfast`, then either re-export `cn` from the package in your helper file or run `npx cnfast migrate` to convert an existing `clsx`, `classnames` or `tailwind-merge` project. On a shadcn/ui project the README gives `npx shadcn@latest add aidenybai/cnfast/cn`, which rewrites `lib/utils.ts`.
Is cnfast still maintained?
The README states that cnfast will no longer be maintained in favor of shadcn's `cn`, and recommends using that package instead. The last push to the repository was on 2026-09-01, with the most recent release being `cnfast@0.2.0` on the same day.
Community notes