The problem: Tailwind v4 is installed correctly and the build runs clean, but almost none of your utility classes actually generate — the page loads with barely any styling.
Environment: Laravel 11.x/12.x, Tailwind CSS 4.x, @tailwindcss/vite plugin, Blade templates, Livewire components mixed in.
The Error
Just like the classic v3 purge issue, this one throws no exception — the build succeeds and produces a suspiciously tiny CSS file:
$ npm run build
vite v5.4.2 building for production...
✓ 41 modules transformed.
public/build/assets/app-2b8f4d7a.css 3.86 kB │ gzip: 1.05 kB
✓ built in 940ms
// a real utility set with Blade + Livewire views usually lands
// somewhere around 15-30kB — 3.86kB means Tailwind barely
// scanned anything for class names
Why It Happens
Tailwind v4 dropped the JS content array from tailwind.config.js entirely — there often isn't a config file at all anymore. Instead, source detection now happens two ways: automatic heuristic scanning from wherever your CSS entry file lives, plus explicit @source directives you add yourself for anything the automatic scan misses.
The automatic scan is good at finding files near your CSS entry point, but it reliably misses a few categories that are extremely common in a Laravel app:
- Blade views living outside the typical scan radius — package views, admin panel views, or anything under
vendor/that renders Tailwind classes (Filament panels, third-party UI packages). - Laravel's own compiled view cache in
storage/framework/views/, which won't get picked up automatically, and matters if you're referencing classes conditionally in ways the raw Blade source doesn't show clearly. - Livewire component classes generated inside PHP methods rather than directly in a
.blade.phpfile, since the scanner is looking for files, not evaluated PHP output. - Classes referenced only inside JS/TS files (Alpine.js expressions building class strings, or a JS-driven component) that live in a folder structure the heuristic doesn't traverse by default.
The Fix
Add explicit @source directives in your CSS entry file, right after the Tailwind import, covering every location the automatic scan might miss:
@import "tailwindcss";
@source "../../resources/views/**/*.blade.php";
@source "../../resources/js/**/*.{js,ts,vue}";
@source "../../storage/framework/views/*.php";
@source "../../vendor/filament/**/*.blade.php";
Paths are relative to the CSS file itself, not your project root — this trips people up constantly. If app.css lives in resources/css/, a directive pointing at resources/views needs ../ to climb back out of css/ first.
For any third-party package (an admin panel, a UI kit) rendering Tailwind classes from its own vendor directory, add an explicit @source line pointing straight at that package's Blade views — Tailwind won't infer it from your app structure alone.
Step-by-Step
- Run
npm run buildand check the CSS output size — a file well under 10kB with a real Blade/Livewire app is a strong signal of under-scanning. - Open your CSS entry file and check whether any
@sourcelines exist at all below the@import "tailwindcss";line. - Add
@sourcedirectives forresources/views/**/*.blade.php, any JS/TS folders with class strings, andstorage/framework/views/*.php. - If you're using Filament, Livewire's own component packages, or any third-party admin/UI package, add a dedicated
@sourceline pointing at that package'svendor/path. - Double-check every path is relative to the CSS file's own location, not the project root — count your
../segments against the actual folder depth. - Rebuild and confirm the CSS file size jumps up to a realistic range before redeploying.
"bg-{$color}-500"), no amount of @source configuration will fix it — the scanner only ever sees literal, complete class strings in the files it reads, never the result of a runtime string concatenation. That's a separate problem from source detection and needs a lookup array or a Tailwind @source inline(...) safelist-style declaration instead, not a broader glob.
Still getting a tiny CSS file after adding your sources? Send me your CSS entry file on the Contact page and I'll help pinpoint what's missing.