When you have multiple apps in a monorepo, you want consistent design tokens: colors, typography, spacing, shadows. Copy-pasting a Tailwind config between apps doesn't scale. Every time you tweak a color, you have to update it everywhere.
Tailwind v4 makes this simpler. The new CSS-first configuration with @theme means your design tokens live in a plain CSS file. In a pnpm/npm workspaces based monorepo you can put that CSS file in its own package and share it just as you'd do with your TypeScript packages.
This article walks through the mechanics of how to set that up. We'll create a shared styles package, consume it from multiple apps, and automate the Tailwind content scanning so it all stays in sync.
The Workspace Structure
For the purpose of this demo I just created two apps and a shared styles project.
1apps/
2 shop/ # React + Vite app
3 admin/ # React + Vite app
4packages/
5 shared/
6 styles/ # Shared design tokens
7Both apps use the same colors and typography, but they're completely independent otherwise.
Step 1: Create the Shared Styles Package
Create a new folder in packages/shared/styles. Create a package.json with the following content:
1// packages/shared/styles/package.json
2{
3 "name": "@org/shared-styles",
4 "version": "0.0.1",
5 "type": "module",
6 "main": "./src/globals.css",
7 "exports": {
8 ".": "./src/globals.css",
9 "./globals.css": "./src/globals.css"
10 }
11}
12There's no build step involved. All we want to do is tell your package manager (pnpm/npm) where to find our @org/shared-styles package so we can import it.
The key is the exports field pointing directly to the CSS file. Any consumer can @import '@org/shared-styles' and get the tokens.
Here's an example of such CSS file using Tailwind v4's @theme directive:
1/* packages/shared/styles/src/globals.css */
2@theme {
3 --color-primary: oklch(55% 0.19 260);
4 --color-primary-light: oklch(84% 0.07 255);
5 --color-primary-dark: oklch(40% 0.17 262);
6
7 --color-secondary: oklch(52% 0.14 175);
8 --color-secondary-light: oklch(84% 0.08 175);
9
10 --color-ink: oklch(26% 0.05 264);
11 --color-ink-light: oklch(66% 0.01 258);
12 --color-ink-lighter: oklch(92% 0.003 254);
13
14 --color-canvas: oklch(97% 0.002 252);
15 --color-success: oklch(55% 0.16 147);
16 --color-error: oklch(59% 0.19 38);
17
18 --font-sans: system-ui, -apple-system, sans-serif;
19 --shadow-md: 0 4px 12px oklch(0% 0 0 / 10%);
20 --radius-md: 0.5rem;
21}
22These become Tailwind utilities automatically. --color-primary gives you bg-primary, text-primary, border-primary, etc.
Step 2: Consume the Shared Styles in an App
Each app needs three things:
1. The @tailwindcss/vite plugin in vite.config.ts:
1import tailwindcss from '@tailwindcss/vite';
2
3export default defineConfig(() => ({
4 plugins: [react(), tailwindcss(), nxViteTsPaths()],
5 // ...
6}));
72. A dependency on the shared styles in package.json:
1{
2 "devDependencies": {
3 "@org/shared-styles": "workspace:*"
4 }
5}
63. A CSS entry point that imports Tailwind and the shared tokens:
1/* apps/shop/src/styles.css */
2@import 'tailwindcss';
3@import '@org/shared-styles';
4That's it. You can now use bg-primary, text-ink, shadow-md, and all the other tokens from your shared package in any component.
The shop app uses bg-primary for its header.

The admin app uses bg-secondary. Same tokens, different choices.

Automating @source Directives
Tailwind v4 needs @source directives to know which files to scan for utility classes. In a monorepo, that means pointing at every library your app depends on. Maintaining those paths by hand gets fragile fast.
Nx has sync generators that can automate this. The @juristr/nx-tailwind-sync package reads the project dependency graph and auto-manages @source directives on every build. For a deeper walkthrough on how this works, check out this blog post.
If you're not using Nx yet, you can add it to any existing pnpm or npm workspace by running nx init in the root of your project. It picks up your existing package.json scripts and workspace structure without requiring changes. From there you can wire up the sync generator.
1npx nx@latest init
2Check out our pnpm + Nx course for a step-by-step walkthrough of adding Nx to an existing workspace.
Full Example
The complete working example is on GitHub: juristr/demo-monorepo-share-tailwind-styles.
Clone it, run pnpm install, then pnpm nx dev shop or pnpm nx dev admin to see both apps using the shared design tokens.





