DEV Community

Cover image for 🚨 The Hidden Pitfall: Mixing Tailwind CSS v3 and v4 in Production
Wishot Cipher🎭
Wishot Cipher🎭

Posted on

🚨 The Hidden Pitfall: Mixing Tailwind CSS v3 and v4 in Production

When I built an AI-powered chatbot for my portfolio using React, Vite, and Tailwind CSS v4, everything worked beautifully β€” until deployment.

Once I pushed to Vercel, the build crashed hard.

The cause?

πŸ‘‰ Mixing Tailwind CSS v3 and v4 components in the same project.

Here’s what happened, what I learned, and how I fixed it.


πŸ“‹ Table of Contents

  1. The Setup: What I Was Building
  2. The Mistake: Installing @tailwindcss/typography
  3. Why It Worked Locally But Failed on Vercel
  4. The Root Cause: Version Conflicts
  5. The Solution: Clean Migration to v4
  6. Custom Typography: Better Than the Plugin
  7. Complete Setup Guide
  8. Key Takeaways

πŸš€ The Setup: What I Was Building

I was creating an AI chatbot for my portfolio with these features:

  • Frontend: React 18 + Vite 6
  • Styling: Tailwind CSS v4
  • AI Integration: Groq API (Llama 3.1 70B Versatile)
  • Markdown Rendering: react-markdown + remark-gfm
  • Deployment: Vercel

The chatbot needed to render AI messages with bold, italics, code blocks, lists, and links β€” so I reached for @tailwindcss/typography.


❌ The Mistake: Installing @tailwindcss/typography

I ran this:

npm install @tailwindcss/typography
Enter fullscreen mode Exit fullscreen mode

Then updated my component:

{isBot ? (
  <div className="prose prose-invert prose-sm md:prose-base">
    <ReactMarkdown remarkPlugins={[remarkGfm]}>
      {message.text}
    </ReactMarkdown>
  </div>
) : (
  <div className="text-sm md:text-base">{message.text}</div>
)}
Enter fullscreen mode Exit fullscreen mode

Locally, everything worked perfectly.

AI responses looked clean and styled β€” until Vercel rejected the build.


πŸ€” Why It Worked Locally But Failed on Vercel

Locally, the dev server was lenient:

  • Vite dev server ignores strict dependency rules
  • Cached dependencies hid conflicts
  • Development builds don’t tree-shake or optimize

But Vercel’s production build was strict:

Error: The `@tailwindcss/typography` plugin is designed for Tailwind CSS v3.x
but you are using Tailwind CSS v4.x. These versions are incompatible.
Enter fullscreen mode Exit fullscreen mode

Vercel installs fresh dependencies and performs strict checks β€” so it caught what local dev ignored.


πŸ” The Root Cause: Version Conflicts

In package.json, I had:

"devDependencies": {
  "tailwindcss": "^4.1.14"
}
Enter fullscreen mode Exit fullscreen mode

But running this:

npm list tailwindcss
Enter fullscreen mode Exit fullscreen mode

Revealed this:

β”œβ”€β”€ tailwindcss@4.1.14
└─┬ @tailwindcss/typography@0.5.10
  └── tailwindcss@3.4.1  ← Hidden dependency!
Enter fullscreen mode Exit fullscreen mode

The typography plugin pulled in Tailwind v3, creating a version conflict.

Feature Tailwind v3 Tailwind v4
Config tailwind.config.js CSS-first (@import "tailwindcss")
PostCSS Required Optional (@tailwindcss/vite)
Plugins JS config CSS or standalone packages
Build PostCSS Vite-native

Mixing both leads to:

  • ⚠️ Conflicting PostCSS transforms
  • ⚠️ Duplicate utility generation
  • ⚠️ Broken configuration detection
  • ⚠️ Build failures

βœ… The Solution: Clean Migration to v4

Step 1: Remove v3 Dependencies

npm uninstall @tailwindcss/typography postcss autoprefixer
rm tailwind.config.js postcss.config.js
Enter fullscreen mode Exit fullscreen mode

Step 2: Verify a Clean v4 Setup

Your package.json should include only:

"devDependencies": {
  "tailwindcss": "^4.1.14",
  "@tailwindcss/vite": "^4.1.14",
  "vite": "^6.0.5",
  "@vitejs/plugin-react": "^4.3.4"
}
Enter fullscreen mode Exit fullscreen mode

Step 3: Update Vite Config

// vite.config.ts
import { defineConfig } from 'vite'
import react from '@vitejs/plugin-react'
import tailwindcss from '@tailwindcss/vite'

export default defineConfig({
  plugins: [react(), tailwindcss()],
})
Enter fullscreen mode Exit fullscreen mode

Step 4: Clean CSS Import

/* src/index.css */
@import "tailwindcss";
/* No need for @tailwind base; etc. */
Enter fullscreen mode Exit fullscreen mode

Step 5: Reinstall Everything

rm -rf node_modules package-lock.json
npm install
Enter fullscreen mode Exit fullscreen mode

🎨 Custom Typography: Better Than the Plugin

Instead of using the plugin, I built my own lightweight typography system β€” fully compatible with v4, more customizable, and no dependency conflicts.

Example: src/index.css

@import "tailwindcss";

.markdown-prose {
  line-height: 1.75;
  color: rgb(229 231 235);
}
.markdown-prose a {
  color: rgb(34 211 238);
  text-decoration: none;
  transition: color 0.2s;
}
.markdown-prose a:hover {
  text-decoration: underline;
  color: rgb(6 182 212);
}
.markdown-prose code {
  background: rgba(255,255,255,0.1);
  padding: 0.25rem 0.5rem;
  border-radius: 0.375rem;
  font-family: 'Courier New', monospace;
  color: rgb(249 168 212);
}
.markdown-prose pre {
  background: rgba(0,0,0,0.3);
  border-radius: 0.5rem;
  padding: 1rem;
  overflow-x: auto;
}
Enter fullscreen mode Exit fullscreen mode

Component Update:

<div className="markdown-prose">
  <ReactMarkdown remarkPlugins={[remarkGfm]}>
    {message.text}
  </ReactMarkdown>
</div>
Enter fullscreen mode Exit fullscreen mode

🧩 Complete Setup Guide

1. Install Dependencies

npm install react react-dom react-markdown remark-gfm
npm install -D vite @vitejs/plugin-react tailwindcss @tailwindcss/vite
Enter fullscreen mode Exit fullscreen mode

2. Project Structure

my-project/
β”œβ”€β”€ src/
β”‚   β”œβ”€β”€ index.css
β”‚   β”œβ”€β”€ main.tsx
β”‚   └── components/
β”‚       └── ChatBot.tsx
β”œβ”€β”€ vite.config.ts
└── package.json
Enter fullscreen mode Exit fullscreen mode

3. Test for Conflicts

npm list tailwindcss
Enter fullscreen mode Exit fullscreen mode

βœ… Only v4 should appear


🎯 Key Takeaways

πŸ’‘ What I Learned

  1. Local β‰  Production – Always test production builds locally.
  2. Peer Dependencies Matter – npm list <package> is your friend.
  3. Tailwind v4 β‰  v3 – It’s a full architecture shift.
  4. Custom CSS Wins – Fewer dependencies, cleaner builds.
  5. Vercel Is Strict – And that’s a good thing.

βœ… Do

  • Test production builds before deploy
  • Read plugin compatibility docs
  • Keep dependencies minimal

❌ Don’t

  • Mix v3 and v4 packages
  • Ignore peer dependency warnings
  • Assume local dev = production ready

πŸ”— Resources


πŸ’¬ Final Thoughts

Mixing Tailwind v3 and v4 is like trying to run diesel in an electric car β€” they’re built differently.

By going all-in with Tailwind v4 and replacing the typography plugin, I ended up with:

  • ⚑ Faster builds
  • 🎨 Fully custom styles
  • πŸš€ 100% production compatibility
  • πŸ”§ Easier maintenance

If you’re upgrading β€” migrate cleanly, don’t mix.


πŸ™‹β€β™‚οΈ Questions?

Found this helpful? Drop a comment or connect with me:

🌍 Connect with Me


Last updated: October 2024

Tailwind CSS: v4.1.14 β€’ React: 18.3.1 β€’ Vite: 6.0.5

Top comments (0)