Skip to content

Monorepo & Content Scope

If you use csszyx inside a monorepo and your build fails with something like Cannot find module './h.cur', an invalid url() in your CSS, or a cryptic hashing crash deep in the bundler — this page is the fix. It is a one-time, two-line change to your CSS entry, and it is not specific to any framework: it applies to Vite, Next.js (webpack and Turbopack), Astro, and any bundler running Tailwind v4.

Tailwind v4 has automatic content detection — no content: [...] array. It picks a base directory and scans it for class names. In a monorepo, that base climbs up to the workspace root, so Tailwind scans every package — and the files it scans are not just your components.

Tailwind ignores node_modules, .gitignored files, binaries, CSS, and lockfiles — but it does not ignore .md, .mdx, or .txt. Documentation is full of class names written as examples: a README code block, an MDX snippet, an AI-context file like llms-full.txt. Tailwind can’t tell “example in the docs” from “class in my app”, so it generates CSS for them — including arbitrary-value classes that compile to broken url(...) rules.

Disable automatic detection and tell Tailwind exactly what to scan. csszyx already auto-injects an @source for the classes it generates, so you only add your own templates.

src/index.css
@import "tailwindcss" source(none);
@source ".."; /* your package root, relative to this CSS file */

source(none) turns off the climb-to-the-workspace-root scan; the explicit @source adds back only your package. This is the most reliable form — a narrowing source("..") alone is not enough, because automatic detection can still escape the base in some bundler pipelines.

Disable detection, then list what to scan. Deterministic; nothing leaks in.

@import "tailwindcss" source(none);
@source ".."; /* this package */
@source "../../packages/ui/src"; /* a shared UI lib you import classes from */

source(none) only affects scanning. If you generate class names dynamically (or need a class that appears in no file), safelist it with @source inline(...) — it supports brace expansion and ranges:

@source inline("underline");
@source inline("{hover:,focus:,}bg-blue-{50,{100..900..100},950}");

csszyx compiles your sz props to Tailwind classes and writes them to a generated safelist file (csszyx-classes.html), then auto-injects an @source pointing at it. That is why, even with source(none), your csszyx styles still emit — the plugin already registered its own source. You only ever scope your own templates.