Fixed: Tailwind Config Changes Not Reflecting After npm run dev

The problem: Editing tailwind.config.js — new colors, extended spacing, custom fonts — doesn't reflect in the browser at all, even with npm run dev still running.

Environment: Laravel 11, Tailwind CSS 3.x, Vite 5, npm run dev (watch mode)

The Error

● ● ●  behavior (no console error)
No JS/build error thrown.
Added `brand: '#E8A33D'` to theme.extend.colors,
used class="text-brand" in Blade — element renders
with no color applied. Vite terminal shows no rebuild.

Why It Happens

Vite's dev server watches your source files (Blade, Vue, JS, CSS) for changes and triggers HMR automatically — but tailwind.config.js sits outside that normal watch scope in some setups, because it's a build-tool configuration file, not application source. Whether it's watched depends entirely on how the Tailwind Vite plugin (or PostCSS pipeline) is wired up:

1. Using the standalone @tailwindcss/postcss setup without Vite's config-file watching enabled means changes to tailwind.config.js require a full dev server restart — PostCSS re-reads the config only when its own process restarts, not on every file save.

2. A stale Vite dependency cache (node_modules/.vite) can hold onto an old compiled version of the Tailwind plugin's output, especially if the config change also touches something Vite pre-bundles.

3. Typo'd or misplaced theme keys — extending colors at the top level of theme instead of inside theme.extend silently replaces Tailwind's entire default color palette rather than adding to it, which can look like "the config isn't working" when actually it's working differently than expected.

The Fix

First, double-check the config structure — new values almost always belong inside extend, not as siblings of it:

tailwind.config.js
module.exports = {
    theme: {
        - colors: {
-     brand: '#E8A33D',
- },
        extend: {
            colors: {
                brand: '#E8A33D',
            },
        },
    },
}

Then fully restart the Vite dev server rather than trusting HMR to pick up config changes on its own:

# Ctrl+C to stop the running dev server, then:
rm -rf node_modules/.vite
npm run dev

If restarts still don't pick up the change, confirm your vite.config.js actually includes the Tailwind config file in its watched paths (needed in some custom multi-config-file setups):

vite.config.js
export default defineConfig({
    server: {
        watch: {
            ignored: ['!**/tailwind.config.js'],
        },
    },
});

Step-by-Step

  1. Open tailwind.config.js and confirm any custom values sit inside theme.extend, not directly under theme.
  2. Stop the running npm run dev process completely (Ctrl+C) — don't rely on it picking up config changes live.
  3. Delete Vite's cache: rm -rf node_modules/.vite.
  4. Restart with npm run dev and confirm the terminal shows a fresh compile with no errors.
  5. Hard-refresh the browser and confirm the new class (e.g. text-brand) now applies visually.
  6. If it still doesn't work, run npx tailwindcss --help to confirm you're not accidentally running two conflicting Tailwind installations (a common leftover from Laravel Mix-to-Vite migrations).

Edge case: If you're using Tailwind's @config directive inside a CSS file to point to a non-default config path (multi-theme or multi-tenant setups), Vite's file watcher may only be tracking the default tailwind.config.js location — a config file at a custom path needs to be added explicitly to vite.config.js's watch list, or changes to it will never trigger a rebuild no matter how many times you restart the dev server.

Still not seeing config changes take effect? Reach out on the Contact page and I'll help debug your build setup.

Advertisement
Advertisement