Fix Knip False Positives with TailwindCSS v4

Learn how to configure Knip to work with TailwindCSS v4's new @plugin and @import directives using custom compilers. Eliminate false positives and keep your dependency reports clean.

3 min read View on GitHub

What is Knip?

Knip helps declutter JavaScript and TypeScript projects by detecting dead exports, unused files, and dependencies. It does this intelligently using a plugin system modeled after real-world tooling and frameworks. This fine-grained approach results in an accurate representation of dead code.

To get started with Knip, run:

Terminal window
pnpm create @knip/config

Add a script to your package.json:

package.json
{
"scripts": {
"knip": "knip"
}
}

Or just run it directly:

Terminal window
pnpx knip

Out of the box, Knip technically works with Tailwind CSS v4, but not perfectly. Its lack of support for Tailwind’s new @plugin and @import directives can cause false positives.

What changed in Tailwind CSS v4?

Tailwind CSS v4 introduced a new configuration approach that is CSS-first, which allows for imports and plugins. However, Knip doesn’t scan these directives by default, which leads to false positives. For example, if you have a Tailwind CSS file like this:

@import "tailwindcss";
@plugin "@tailwindcss/typography";
@plugin "daisyui";
@plugin "@iconify/tailwind4";

When you run knip, you might see output like this:

Terminal window
Unused devDependencies (4)
@iconify/tailwind4 package.json:29:6
@tailwindcss/typography package.json:32:6
daisyui package.json:36:6
tailwindcss package.json:45:6
error: script "knip" exited with code 1

One quick fix is to ignore these dependencies in your Knip configuration file:

knip.config.ts
import type { KnipConfig } from "knip";
export default {
ignoreDependencies: [
"@iconify/tailwind4",
"@tailwindcss/typography",
"daisyui",
"tailwindcss",
],
} satisfies KnipConfig;

We use satisfies KnipConfig to ensure our config matches the expected structure. It’s a TypeScript safety check, not required for runtime.

Knip supports a custom compilers configuration option, and with a bit of regex magic, we can teach it to understand Tailwind’s directives like @import and @plugin.

How to configure Knip for Tailwind CSS v4?

knip.config.ts
import type { KnipConfig } from "knip";
export default {
compilers: {
css: (text: string) => {
// Converts @import and @plugin directives into JS-style imports
return [...text.matchAll(/@(?:import|plugin)\s+["']([^"']+)["']/g)]
.map(([_, dep]) => `import "${dep}";`)
.join("\n");
},
},
} satisfies KnipConfig;

And if you’ve modified knip’s project field, be sure to include .css files as well:

knip.config.ts
import type { KnipConfig } from "knip";
export default {
project: "**/*.{ts,tsx,css}",
} satisfies KnipConfig;

This prevents false positives, keeps your reports clean, and avoids accidentally removing real dependencies.

How does this work?

This configuration defines a custom compiler for CSS files. It looks for @import and @plugin directives using a regular expression and transforms them into JavaScript-style import statements that Knip can understand and analyze like regular module imports.

This borrows from Knip’s own css compiler example.

matchAll is used to find all matches of a regular expression in a string.

The regex pattern @(?:import|plugin)\s+["']([^"']+)["'] breaks down as:

  • @(?:import|plugin) - Matches either @import or @plugin
  • \s+ - Matches one or more whitespace characters
  • ["']([^"']+)["'] - Captures the dependency name inside quotes

In the earlier example, it would return:

[
['@import "tailwindcss"', "tailwindcss"],
['@plugin "@tailwindcss/typography"', "@tailwindcss/typography"],
['@plugin "daisyui"', "daisyui"],
['@plugin "@iconify/tailwind4"', "@iconify/tailwind4"],
];

You can further learn about regex at regex101.

Then map transforms each match into an import statement using the captured dependency name, and the join("\n") combines them into a single string to make it look like valid JavaScript/TypeScript code.

Once that’s in place, running knip will no longer flag these dependencies:

Terminal window
✂️ Excellent, Knip found no issues.

Tailwind’s new config is great, but Knip doesn’t know what to do with @plugin or @import by default. This setup bridges that gap and keeps your reports clean.

Thank you for reading ❤️.

Back to all posts