Streamdown Tailwind @source in monorepos
TL;DR
- Add an
@sourceentry that resolves from your CSS file to the installedstreamdown/dist/*.jsfiles.- Do not assume a monorepo always means root
node_modules; Bun and pnpm may expose packages through app-local symlinks.- Import
streamdown/styles.cssseparately when you need Streamdown's shipped animation styles.- If code block colours, layout, or action buttons look wrong, verify the
@sourcepath first.
Streamdown uses Tailwind utility classes inside its distributed JavaScript. Tailwind v4 does not scan ignored dependencies automatically, so you must add a CSS @source directive for Streamdown.
The important part is not whether your project is a monorepo. The important part is which node_modules path Tailwind can resolve from the stylesheet that imports Tailwind.
Configure Tailwind v4
Add Streamdown's stylesheet import and Tailwind source path in the CSS file that imports Tailwind:
@import "streamdown/styles.css" and @source solve different problems:
@import "streamdown/styles.css"loads Streamdown's shipped CSS, such as animation keyframes.@sourcetells Tailwind to scan Streamdown's built files for utility class names.
Pick the path from your install layout
The @source path is relative to the CSS file, not to the repository root.
For a CSS file at apps/web/styles/globals.css, check the package location from the repo root:
If Streamdown is exposed at apps/web/node_modules/streamdown, use:
If Streamdown is exposed at the repository root, use:
Why this happens
Streamdown's code rendering relies on Tailwind utilities generated from package source. If Tailwind does not see those class names during scanning, they never make it into the output CSS.
Monorepos make this easy to get wrong because different package managers expose dependencies differently. npm workspaces may hoist packages to root node_modules. Bun and pnpm may store packages in a central or virtual store, then expose them through workspace-local node_modules symlinks.
Tailwind does not need the package store path. It needs a path that resolves from your CSS file to the package files it should scan.
Common symptoms:
- code blocks render, but token colors look flat
- light/dark token differences barely show
- copy/download buttons appear below the language label instead of in the same header row
- computed layout classes such as
-mt-10,sticky, orjustify-endare missing from the generated CSS - no build errors, just weak syntax highlighting
How to verify quickly
- Inspect the code block in DevTools.
- Confirm Streamdown markup is present (e.g.
data-streamdown="code-block-body"). - Check whether the
@sourcepath exists from your CSS file's point of view. - Search your built CSS for a Streamdown-only utility class used by the broken element.
For example, if code block actions are on the wrong row, search the built CSS for:
If those utilities are missing, Tailwind did not scan the files that contain Streamdown's code block classes.
Plugin packages
Streamdown plugins can also contain Tailwind classes. If you use plugin packages, add @source entries for the packages that require them.
For example, if your CSS file is at apps/web/styles/globals.css and the packages are exposed through apps/web/node_modules, use:
Only keep entries for packages you actually install and use.
Lesson learned
With Streamdown + Tailwind in monorepos, path correctness matters more than the word "monorepo". Use a CSS-relative @source path to the node_modules directory that actually exposes Streamdown, then debug dark-mode-specific issues separately.