{"record":{"id":"befb52891d984e33","repo":"shadcn-ui/ui","slug":"the-cn-migration-requires-tailwind-css-v4-and-tail","errorCode":null,"errorMessage":"The cn migration requires Tailwind CSS v4 and tailwind-merge v3. Tailwind CSS v3 projects should continue using tailwind-merge v2.","messagePattern":"The cn migration requires Tailwind CSS v4 and tailwind-merge v3\\. Tailwind CSS v3 projects should continue using tailwind-merge v2\\.","errorType":"exception","errorClass":"Error","httpStatus":null,"severity":"error","filePath":"packages/shadcn/src/migrations/cn/index.ts","lineNumber":144,"sourceCode":"  cwd: string,\n  migratedPackages: Set<OldPackage>\n) {\n  if (!migratedPackages.has(\"tailwind-merge\")) {\n    return\n  }\n\n  const packageInfo = getPackageInfo(cwd, false)\n  const tailwindVersion = findDependencyVersion(packageInfo, \"tailwindcss\")\n  const tailwindMergeVersion = findDependencyVersion(\n    packageInfo,\n    \"tailwind-merge\"\n  )\n\n  if (\n    (getDeclaredMajor(tailwindVersion) ?? 4) < 4 ||\n    (getDeclaredMajor(tailwindMergeVersion) ?? 3) < 3\n  ) {\n    throw new Error(\n      \"The cn migration requires Tailwind CSS v4 and tailwind-merge v3. Tailwind CSS v3 projects should continue using tailwind-merge v2.\"\n    )\n  }\n}\n\nfunction findDependencyVersion(\n  packageInfo: ReturnType<typeof getPackageInfo>,\n  packageName: string\n) {\n  return (\n    packageInfo?.dependencies?.[packageName] ??\n    packageInfo?.devDependencies?.[packageName] ??\n    packageInfo?.optionalDependencies?.[packageName] ??\n    packageInfo?.peerDependencies?.[packageName]\n  )\n}\n\nfunction getDeclaredMajor(version?: string) {","sourceCodeStart":126,"sourceCodeEnd":162,"githubUrl":"https://github.com/shadcn-ui/ui/blob/5c7072da672b0048bc6771e3204063a2537df91a/packages/shadcn/src/migrations/cn/index.ts#L126-L162","documentation":"The cn migration rewrites cn() helpers built on tailwind-merge v3 semantics, which only work with Tailwind CSS v4. assertTailwindCompatibility reads tailwindcss and tailwind-merge versions from package.json (dependencies/devDependencies/optional/peer) and throws if the declared major of either is below the required minimum (v4 and v3 respectively; workspace/protocol specifiers are treated as satisfying).","triggerScenarios":"migrateCn detecting tailwind-merge usage in migrated files while package.json declares tailwindcss 3.x or tailwind-merge 2.x (or neither is declared at a valid semver major).","commonSituations":"Upgrading a Tailwind v3 project to the new cn utility without first migrating Tailwind itself; a monorepo app that still pins tailwind-merge@^2 while others use v3; the packages missing from package.json entirely so majors fall back to 4/3 — the throw only fires on a declared lower major.","solutions":["Upgrade to Tailwind CSS v4 (`npx @tailwindcss/upgrade`) before running the cn migration.","Upgrade tailwind-merge to v3: `npm install tailwind-merge@^3`.","If you must stay on Tailwind v3, keep tailwind-merge v2 and do not run the cn migration for that project.","Check package.json for stale pins/resolutions (e.g. overrides forcing tailwind-merge@2) and remove them."],"exampleFix":"// before (package.json)\n\"tailwindcss\": \"^3.4.0\",\n\"tailwind-merge\": \"^2.2.0\"\n// after\n\"tailwindcss\": \"^4.0.0\",\n\"tailwind-merge\": \"^3.0.0\"","handlingStrategy":"validation","validationCode":"import { readFileSync } from 'fs'\nconst pkg = JSON.parse(readFileSync('package.json', 'utf8'))\nconst deps = { ...pkg.dependencies, ...pkg.devDependencies }\nif (parseInt(deps['tailwindcss']?.match(/\\d+/)?.[0] ?? '4', 10) < 4 ||\n    parseInt(deps['tailwind-merge']?.match(/\\d+/)?.[0] ?? '3', 10) < 3) {\n  throw new Error('Upgrade to tailwindcss@4 and tailwind-merge@3 before migrating')\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Migrate Tailwind v3 -> v4 with the official upgrade tool before running the cn migration.","Keep tailwind-merge on v3 across all monorepo workspaces.","Remove package overrides/resolutions that pin tailwind-merge to v2."],"tags":["version-compatibility","tailwind","dependencies"],"backgroundTag":"incompatible-source-type","analyzedSha":"5c7072da672b0048bc6771e3204063a2537df91a","analyzedAt":"2026-09-07T00:08:47.579Z","contentChangedAt":"2026-09-07T00:08:47.579Z","schemaVersion":2},"datasetVersion":"2026-09-14T05:17:10.506Z"}