afterbuild/ops
ERR-273/Tailwind · Build
ERR-273
Tailwind utility classes render in development but are stripped from the production bundle

appears when:After `next build` or any bundler step that runs Tailwind in production mode with a purge-configured content array

Tailwind CSS not working in production

Tailwind's production build emits only classes it can statically see. If the content array misses a folder or a class is built from a template string, those utilities never ship.

Last updated 17 April 2026 · 6 min read · By Hyder Shah
Direct answer
Tailwind CSS not working in production means the JIT compiler purged classes it never found in your configured source paths. Fix by listing every folder that renders JSX in the content array (v3) or with @source directives (v4), and safelist class names you build from template strings. Never rely on dev mode to catch this.

Quick fix for Tailwind not working in production

tailwind.config.js
javascript
01// tailwind.config.js (v3) — list every folder that renders class names02/** @type {import('tailwindcss').Config} */03module.exports = {04  content: [05    "./src/**/*.{js,ts,jsx,tsx,mdx}",06    "./app/**/*.{js,ts,jsx,tsx,mdx}",07    "./components/**/*.{js,ts,jsx,tsx,mdx}",08    // include any package that exports class-bearing JSX09    "./node_modules/@myorg/ui/dist/**/*.{js,mjs}",10  ],11  safelist: [12    // only classes built at runtime — everything else Tailwind finds on its own13    { pattern: /^bg-(red|green|blue|amber)-(400|500|600)$/ },14  ],15  theme: { extend: {} },16  plugins: [],17};
Paste into tailwind.config.js — covers src, app, components, and any UI package in node_modules

Deeper fixes when the quick fix fails

01 · Tailwind v4 — replace tailwind.config.js with @source in CSS

app/globals.css
css
01/* app/globals.css — Tailwind v4 source declarations */02@import "tailwindcss";03 04@source "../src/**/*.{js,ts,jsx,tsx,mdx}";05@source "../app/**/*.{js,ts,jsx,tsx,mdx}";06@source "../components/**/*.{js,ts,jsx,tsx,mdx}";07/* third-party UI library with class names */08@source "../node_modules/@myorg/ui/dist/**/*.{js,mjs}";09 10@theme {11  --color-lime: oklch(85% 0.2 130);12}
v4 drops tailwind.config.js — all source paths live in the main CSS with @source

02 · Refactor dynamic classes to a literal lookup

components/Badge.tsx
typescript
01// BEFORE — Tailwind cannot see this class02function Badge({ color }: { color: "red" | "green" }) {03  return <span className={`bg-${color}-500`}>ok</span>;04}05 06// AFTER — every possible class is a literal the scanner finds07const badgeClass = {08  red: "bg-red-500 text-red-50",09  green: "bg-green-500 text-green-50",10} as const;11 12function Badge({ color }: { color: keyof typeof badgeClass }) {13  return <span className={badgeClass[color]}>ok</span>;14}
Replace template-literal class names with a typed lookup — the scanner sees every branch

03 · Write a regression Playwright test that checks computed style

e2e/tailwind.spec.ts
typescript
01// e2e/tailwind.spec.ts — fails if the utility is purged02import { test, expect } from "@playwright/test";03 04test("hero has lime background in production", async ({ page }) => {05  await page.goto("/");06  const hero = page.locator('[data-testid="hero-cta"]');07  const bg = await hero.evaluate((el) => getComputedStyle(el).backgroundColor);08  // lime-500 in rgb — if Tailwind purges the class, this becomes rgba(0,0,0,0)09  expect(bg).toBe("rgb(132, 204, 22)");10});
Run in CI against a production build — catches purge regressions the dev server hides

Why AI-built apps hit Tailwind not working in production

Tailwind's JIT compiler walks every file in the content array, extracts class names it recognizes, and emits exactly that set into the final CSS bundle. In dev mode the compiler generates utilities on demand as you type, so every class works whether the array is correct or not. The first time you hit next build or any real production build, Tailwind enforces the list. Classes in files outside the list get purged. Your page ships without the styles that worked five minutes ago on localhost.

AI builders like Lovable, Bolt, and v0 scaffold a content array with ./src/**/* and stop. Later you add an app/ directory or pull components from an @myorg/ui package inside node_modules. Neither is covered. Every class inside those files disappears on build. The error does not surface in dev because JIT papers over it.

The second common source is dynamic class names. A component writes className={`bg-${color}-500`}` where color is a variable. The scanner reads the literal string in the source file, sees no complete class, emits nothing. In dev it works because JIT picks up bg-red-500 the moment it renders. In prod the bundle never contains it. Fix by mapping the variable to a literal lookup table or by safelisting the pattern in the config.

The third source is Tailwind v4 migrations. v4 dropped tailwind.config.js and uses @source directives inside your main CSS. If you installed v4 but left the v3 config in place, Tailwind falls back to defaults, ignores your paths, and produces a tiny bundle. The symptom looks identical to a misconfigured content array.

Tailwind not working in production by AI builder

How often each AI builder ships this error and the pattern that produces it.

AI builder × Tailwind not working in production
BuilderFrequencyPattern
LovableEvery scaffold with TailwindContent array only lists ./src/**/* — misses /app and node_modules UI packages
Bolt.newCommonTemplate-literal class names like `bg-${color}-500` never safelisted
v0CommonMixes Tailwind v3 config with v4 imports — neither takes effect
CursorSometimesForgets to rerun `next build` after editing tailwind.config.js
Replit AgentRarePostCSS plugin order wrong — autoprefixer runs before Tailwind

Related errors we fix

Stop Tailwind not working in production recurring in AI-built apps

Still stuck with Tailwind not working in production?

Emergency triage · $299 · 48h turnaround
We restore service and write the root-cause report.
start the triage →

Tailwind not working in production questions

Why do my Tailwind classes work in development but disappear in production?+
Tailwind's JIT compiler only emits CSS for class names it can statically see in your source files. In development every class is generated on the fly, which hides the problem. In production Tailwind scans the paths listed in the content array and ships only those utilities. If the path list misses a folder, classes in those files get purged. Locally nothing purges, so the bug stays invisible until deploy.
How do I safelist dynamic class names in Tailwind?+
Tailwind cannot infer class names built at runtime from template strings like `bg-${color}-500`. Either write out every possible class in a literal comment so the scanner sees it, or add the classes to the safelist array in tailwind.config.js. Better: map the dynamic value to a fixed object where every branch is a literal class name. Safelisting works but bloats the bundle, so use it only for colors you truly generate at runtime.
What is the difference between Tailwind v3 and v4 config for missing styles?+
Tailwind v4 removed tailwind.config.js in favor of CSS-first configuration. Instead of a content array you declare source files with @source in your main CSS. If you are mid-migration and left a v3 config next to v4 imports, Tailwind silently falls back to defaults and your paths are ignored. Pick one version. For v4 use @source "../**/*.{js,ts,jsx,tsx}" in globals.css.
Can PostCSS order cause Tailwind to break in production?+
Yes. Tailwind must run after autoprefixer in the PostCSS pipeline or nested utilities break. Next.js handles this automatically, but AI-generated custom postcss.config.js files often list plugins in the wrong order. Check that @tailwindcss/postcss (or tailwindcss for v3) appears before autoprefixer. A wrong order fails silently in dev because the JIT compiler bypasses most of the chain.
How long does a full Tailwind production fix take?+
Fifteen minutes for a single missing path in the content array. Thirty minutes if you need to audit dynamic class names and add a safelist. Migration from v3 to v4 or the reverse takes two to four hours because every directive, plugin, and custom color token has to be translated. Our Emergency Triage at $299 covers the fifteen-minute version and ships a Playwright visual test so the regression cannot happen again.
Next step

Ship the fix. Keep the fix.

Emergency Triage restores service in 48 hours. Break the Fix Loop rebuilds CI so this error cannot ship again.

About the author

Hyder Shah leads Afterbuild Labs, shipping production rescues for apps built in Lovable, Bolt.new, Cursor, Replit, v0, and Base44. our rescue methodology.

Sources