Skip to main content
Sources: Context7 /tailwindlabs/tailwindcss.com, /dcastil/tailwind-merge.
Use: Embed as “Research Brief” in PF-77 spec.
STATUS: MIGRATION COMPLETE (2026-04-01). This document was the pre-migration research brief for PF-77. The migration has been executed successfully. For the current post-migration state, see CLAUDE.md (tech stack) and src/index.css (theme configuration). The information below is retained as historical context.

Official upgrade path and prerequisites

  • Node.js 20+ required for @tailwindcss/upgrade.
  • Single migration: Upgrade Tailwind CSS v3 → v4 and tailwind-merge v2 → v3 together. tailwind-merge v3 supports only Tailwind v4; do not upgrade tailwind-merge v3 while staying on Tailwind v3. (Ref: tailwind-merge v2-to-v3 migration.)
  • Official tool:
    npx @tailwindcss/upgrade
    Automates dependency updates, config migration, and template changes. (Ref: Tailwind upgrade guide.)

Confirmed breaking and config changes


Required tools and workflow

  1. Run upgrade tool:
    npx @tailwindcss/upgrade
    (Node 20+; run from project root.)
  2. PostCSS (if not using Vite plugin):
    Replace tailwindcss and autoprefixer with:
    "@tailwindcss/postcss": {}
    in postcss.config.js.
  3. Vite alternative:
    Install tailwindcss and @tailwindcss/vite; in vite.config.ts add tailwindcss() to plugins; in main CSS use @import "tailwindcss";.
  4. Theme/customization:
    Move custom theme (colors, fonts, breakpoints, spacing, shadows, keyframes) into @theme { ... } in CSS; extend or override as per Tailwind v4 docs.
  5. tailwind-merge:
    Bump to v3; if using extendTailwindMerge/createTailwindMerge with a prefix, remove the combining character (e.g. tw-tw).

Repo compatibility notes

  • Config: tailwind.config.ts uses darkMode: ['class'], large theme.extend, and tailwindcss-animate. After upgrade, re-assert class-based dark (darkMode: ['class']) and migrate theme to @theme where applicable.
  • Plugin (tailwindcss-animate): Either (1) keep tailwindcss-animate v1.0.7 with Tailwind v4 by loading the JS plugin via the @config directive—keep the plugin entry in tailwind.config.ts and reference it from your main CSS with @config so the plugin is applied, or (2) migrate to a CSS-first animation solution such as tw-animate-css or @iscodex/tailwindcss-animate: remove the tailwindcss-animate plugin from tailwind.config.ts, add the new package, and update your CSS imports to use the new package’s styles. Verify the chosen plugin version is compatible with Tailwind v4 before deployment.
  • CSS entry: src/index.css uses @tailwind base/components/utilities and @layer + @apply. These need to align with v4 CSS-first approach; upgrade tool may rewrite.
  • Utilities: src/shared/lib/utils.ts uses cn() with twMerge(clsx(inputs)) and no custom extendTailwindMerge; bumping tailwind-merge to v3 is sufficient unless a custom prefix is added later.
  • Arbitrary values / theme(): src/shared/ui/sidebar.tsx uses theme(spacing.4) inside calc(). In Tailwind v4, replace with the v4 theme variable form, e.g. calc(var(--spacing-4) - 1px) or calc(--spacing(4) - 1px) (syntax per v4 docs). Update any helper or style string that builds that calc expression accordingly, and verify tailwindcss-animate (or replacement) is v4-compatible before deployment.

  1. Branch: Create a dedicated migration branch (or tag a commit) that captures the pre-migration state of tailwind.config.ts, postcss.config.js (if present), and src/index.css. Prefer version control over copying files into docs/development/backups/ so rollbacks are tracked and the docs folder stays uncluttered.
  2. Run: npx @tailwindcss/upgrade; resolve conflicts; restore class dark mode and custom theme in @theme/config as needed.
  3. Bump: Ensure tailwindcss 4.x and tailwind-merge 3.x in package.json; npm install.
  4. Manual pass: Replace any [--var] with (--var); fix theme() usage if changed; run build and visual pass.
  5. Validate: npm run validate; npm run test:baseline; visual regression on shared UI and key flows.
  6. Rollback: Revert the migration branch or restore from the pre-migration tag/commit; npm install and re-validate.