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.
What’s actually happening
Section titled “What’s actually happening”Tailwind v4 has automatic content detection — no content: [...] array. It picks
a base directory and scans everything under it for class names. How wide that base
is depends on the build: a Vite build roots it at the Vite root, while other setups
root it at the workspace root and scan every package. Either way, the files it scans
are not just your components — a doc or fixture sitting beside your entry counts.
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.
The fix: scope the scan to your package
Section titled “The fix: scope the scan to your package”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.
@import "tailwindcss" source(none);@source "..";That @source is your package root, relative to this CSS file. source(none) turns
off automatic detection entirely; the explicit @source adds back only what you name.
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.
Other ways to scope
Section titled “Other ways to scope”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 */Keep automatic detection but carve out the poisoners. Simpler, but you must name every offending path.
@import "tailwindcss";@source not "../../apps/docs"; /* docs with class examples */@source not "../../**/*.md"; /* and any markdown */Point detection at a sub-tree. Convenient, but less reliable — some pipelines
still climb out of the base, so prefer source(none) if you see leakage.
@import "tailwindcss" source("../src");Safelisting literal classes
Section titled “Safelisting literal classes”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}");How csszyx fits in
Section titled “How csszyx fits in”csszyx compiles your sz props to Tailwind classes and writes them to a generated
safelist file (.csszyx/csszyx-classes.txt), 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. On
Next.js the same directive comes from the @csszyx/unplugin/postcss plugin in
postcss.config, since Turbopack offers no hook into the stylesheet itself.
Workspace packages you compile
Section titled “Workspace packages you compile”The safelist covers every directory the prescan walks, which includes anything you
opted in with compileSources. A vendored design system
beside your app is therefore safe to scope: its sz-compiled classes and the raw
className literals sitting next to them are both written to the safelist, and the
auto-injected @source picks them up wherever the package lives relative to the CSS
file.
The condition is the opt-in. A /packages/ directory that is not in
compileSources is skipped by the prescan, so its classes are absent from the
safelist and source(none) would drop them — that is exactly what the build-end
“skipped by ignore rules” warning is telling you. Add the directory first, confirm
the warning is gone, then scope.
See also
Section titled “See also”- Installation — first-time setup.
- Tailwind CSS — Detecting classes in source files (official
source()/@sourcereference).