Description
I have a Turborepo monorepo set up with the following structure:
root/
├── apps/
│ ├── web/ # Next.js app
│ │ ├── src/
│ │ ├── package.json
│ │ ├── tailwind.config.js # Imports shared config
│ │ └── postcss.config.mjs # Imports shared config
│ ├── docs/ # (optional docs app)
│
├── packages/
│ ├── ui/ # UI component library
│ │ ├── src/
│ │ │ └── styles.css
│ │ ├── dist/
│ │ │ ├── index.js
│ │ │ └── styles.css
│ │ ├── package.json
│ │
│ ├── tailwind-config/ # Shared Tailwind config package
│ │ ├── tailwind.config.js
│ │ ├── postcss.config.mjs
│ │ └── package.json
│
└── package.json (root)
Root package.json
{
"private": true,
"workspaces": ["apps/*", "packages/*"],
"devDependencies": {
"tailwindcss": "^4.1.12",
"@tailwindcss/postcss": "^4.1.12",
"postcss": "^8.5.6",
"turbo": "^2.5.4"
}
}
Shared Tailwind Config (packages/tailwind-config/tailwind.config.js)
import path from "path";
export default {
content: [
path.join(__dirname, "../../apps/**/*.{js,ts,jsx,tsx}"),
path.join(__dirname, "../../packages/**/*.{js,ts,jsx,tsx}")
],
theme: {
extend: {},
},
plugins: [],
};
Shared PostCSS Config (packages/tailwind-config/postcss.config.mjs)
export default {
plugins: {
"@tailwindcss/postcss": {},
},
};
UI Package (packages/ui/package.json)
{
"name": "@astra/ui",
"version": "1.0.0",
"main": "./dist/index.js",
"sideEffects": ["**/*.css"],
"files": ["dist"],
"scripts": {
"build:css": "tailwindcss -i ./src/styles.css -o ./dist/styles.css",
"dev:css": "tailwindcss -i ./src/styles.css -o ./dist/styles.css --watch",
"build": "npm run build:css && tsc"
}
}
Web App Tailwind Config (apps/web/tailwind.config.js)
import config from "@repo/tailwind-config/tailwind.config.js";
export default config;
Web App PostCSS Config (apps/web/postcss.config.mjs)
import config from "@repo/tailwind-config/postcss.config.mjs";
export default config;
Web App Global CSS (apps/web/app/global.css)
@import "@astra/ui/dist/styles.css";
The Problem
The UI components from @astra/ui render, but none of the Tailwind CSS styles are applied.
Even default Tailwind utility classes in apps/web are not working (e.g., bg-red-500 does nothing).
Breakpoints (sm:, md:, etc.) also do not apply.
The Tailwind CLI build in @astra/ui does generate dist/styles.css, but when imported in the web app, styles are still missing.
PostCSS and Tailwind config are both imported from the shared @repo/tailwind-config package.
What I Tried
Deleting node_modules, .turbo, and dist folders and reinstalling dependencies.
Running tailwindcss -i ./src/styles.css -o ./dist/styles.css inside packages/ui.
Verifying that content paths in the shared tailwind.config.js include both apps and packages.
Making sure "sideEffects": ["**/*.css"] is set in
packages/ui/package.json so CSS isn’t tree-shaken.
Importing the built CSS in apps/web/app/global.css.
Question
Why aren’t Tailwind styles applying in my Next.js app when using:
A Turborepo monorepo
A shared Tailwind config package
A separate UI component library that outputs built CSS?
What is the correct way to configure Tailwind so styles are applied
across both the web app and the UI package in this setup?
No AI will ever be as good as well-written, easy-to-digest documentation.
From v4 onwards, there is no tailwind.config.js
by default. This is why you don't see the shared configuration.
From v4 onwards, in CSS-first configuration, it's recommended to declare the sources using @source
, and - if absolutely necessary - the configuration files using the @config
directive, strictly with a relative path.
Something like this:
apps/web/app/global.css
@import "tailwindcss"; /* instead of @tailwind directives */
/* Sources instead of content property */
@source "./../../../apps/**/*.{js,ts,jsx,tsx}";
@source "./../../../packages/**/*.{js,ts,jsx,tsx}";
/* Configurations - If possible, avoid it; */
/* Instead, migrate the external configuration into a CSS-first setup as well, and simply import the external CSS-first configuration into the current one using a standard CSS @import */
@config "./../../../path/to/@repo/tailwind-config/tailwind.config.js";
/* Another CSS-first configurations */
@theme {
/* ... */
}
Tried [...] running
tailwindcss -i ./src/styles.css -o ./dist/styles.css
insidepackages/ui
.
Why? You're using a PostCSS plugin. Why would you want to compile with the CLI? Starting from v4, partly because of things like this, the main TailwindCSS engine, the CLI module, and the PostCSS plugin were separated. They also released a new Vite plugin.
package.json
{ "scripts": { "build:css": "tailwindcss -i ./src/styles.css -o ./dist/styles.css", "dev:css": "tailwindcss -i ./src/styles.css -o ./dist/styles.css --watch", "build": "npm run build:css && tsc" } }
For the reasons mentioned above, the presence of build:css
and dev:css
here also doesn't make sense.
You've installed the PostCSS plugin, so you need to integrate PostCSS into your system, and it can typically be run with the npm run dev
or npm run build
commands.
Otherwise, I don't see the point of using PostCSS. If you want to use the CLI, then the package to install is @tailwindcss/cli
and the command to use is npx
.
Or when using the Standalone version, PostCSS is not needed either.
Or you can revert to TailwindCSS v3, where the JS-based configuration is still easily accessible.
npm remove @tailwindcss/postcss
npm install tailwindcss@3
In v4, however, the goal is a full transition to CSS-first, so sooner or later the JS configuration is expected to be discontinued - similar to when the JIT engine was introduced in v2.