Setting up tailwindcss v4 in a Monorepo with Nuxt


With the latest changes in TailwindCSS v4, setting up Tailwind and having a shared config across your apps in a monorepo can be challenging. In this article, I’ll walk you through how to set up Tailwind and create a shared config that keeps your styles clean, consistent, and DRY across your Nuxt apps.
Let’s roll up our sleeves and get into it!
Tools
Before we start, there are some tools you'll need:
pnpm - a new generation of package management tools that also works for monorepos
Vscode(or any preferred IDE)
Setting up a monorepo
Install pnpm
npm install -g pnpm # install pnpm globally
Create a new directory and initialize the package manager with pnpm
mkdir tailwind-v4-nuxt-monorepo
cd tailwind-v4-nuxt-monorepo
pnpm init
Cloning the repo? Just swap out mkdir tailwind-v4-nuxt-monorepo
for git clone <repository-link>
and you’re good to go.
Once you’ve finished setting up your directory, go ahead and open it in your favorite code editor. If you're using VS Code, you can simply run:
code .
Set up the workspace
To set up the workspace, you have to create pnpm-workspace.yaml
in your project root directory — It’s what tells pnpm which folders to treat as workspaces. For more context, read it up here.
touch pnpm-workspace.yaml # creates a new file
Add these configurations to the pnpm-workspace.yaml
packages:
- 'apps/*'
- 'packages/*'
This tells pnpm that your workspaces include all directories in the apps
and packages
folders.
The apps
folder is basically where your application sits, while the packages folder is where your shared packages are placed
Create your workspace folders
Since the apps
folder will house our applications, let’s go ahead and create it, then spin up our first nuxt app inside
mkdir apps && cd apps # creates a new apps folder and navigates to the folder
Now let’s install nuxt into the apps
folders
pnpm create nuxt web-1 # replace web-1 with your app. name
Congratulations🥳. Your Nuxt app has been installed successfully.
Now, let's create our shared tailwind-config folder in the packages
folder (remember, the packages folder is where your shared packages are placed).
Navigate back to your root folder to create the packages folder.
mkdir packages && cd packages # creates a new packages folder and navigates to the folder
Now let’s create the shared folder. We are going to name it “tailwind-config.”
mkdir tailwind-config
cd tailwind-config
pnpm init # pnpm init would generate package.json file for tailwind-config directory
After running the above command, add "private": true
to the generated package.json file. Your package.json file should look like this:
{
"name": "tailwind-config",
"version": "1.0.0",
"description": "",
"private": true,
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC"
}
The purpose of adding "private": true
is to ensure that the package is not published to NPM or anywhere else. Instead, it is referenced and used locally within our workspace.
At this point, your file structure should look like this:
├── apps
│ └── web-1
│ ├── README.md
│ ├── app.vue
│ ├── nuxt.config.ts
│ ├── package.json
│ ├── public
│ │ ├── favicon.ico
│ │ └── robots.txt
│ ├── server
│ │ └── tsconfig.json
│ └── tsconfig.json
├── package.json
├── packages
│ └── tailwind-config
│ └── package.json
├── pnpm-lock.yaml
├── pnpm-workspace.yaml
Installing Tailwind and setting the shared configuration
After setting up the Nuxt application and the directory for our tailwind-config, let's install tailwindcss.
Let’s start with installing tailwindcss in our tailwind-config
directory and set up the shared configuration
pnpm add --filter tailwind-config tailwindcss
After successfully installing tailwindcss, we will create our index.css
file to set our configurations and import tailwindcss. Here's how to do it:
/* packages/tailwind-config/index.css */
@import "tailwindcss";
Note: Because tailwind-config
is solely for configurations; you don’t need to install @tailwindcss/vite as stated in the tailwind documentation. Using the import works just fine
After creating the index.css
file, change "main": "index.js"
to "main": "index.css"
in your package.json
file, so it sets the entry point when imported(from the apps directory) to the CSS file.
This should be what the modified file should look like
// packages/tailwind-config/package.json
{
"name": "tailwind-config",
"version": "1.0.0",
"description": "",
"private": true,
"main": "index.css",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"keywords": [],
"author": "",
"license": "ISC",
"dependencies": {
"tailwindcss": "^4.1.7"
}
}
Integrating the shared tailwind-config from the Nuxt app
Now let’s go over to the apps
directory to install tailwindcss and use the configuration we just set up
pnpm add --filter web-1 tailwindcss @tailwindcss/vite
Once Tailwind is installed in your Nuxt app, there are a few tweaks you’ll need to make to get everything working just right:
In the
nuxt.config.ts
, first addimport tailwindcss from "@tailwindcss/vite";
.Next, you add the imported tailwindcss to the vite.plugins in your
nuxt.config.ts
vite: { plugins: [ tailwindcss(), ], },
So your
nuxt.config.ts
file should be updated to:import tailwindcss from "@tailwindcss/vite"; // https://nuxt.com/docs/api/configuration/nuxt-config export default defineNuxtConfig({ compatibilityDate: '2025-05-15', devtools: { enabled: true }, vite: { plugins: [ tailwindcss(), ], }, })
Create your
assets/css/main.css
file and import the shared configuration/* /apps/web-1/assets/css/main.css */ @import "tailwind-config"
Remember, you are importing the configurations from
packages/tailwind-config/index.css
and the file already has the@import “taildwincss"
, so there is no need to add the@import “taildwincss"
again in theapps/web-1/assets/css/main.css
file. That’s the beauty of using a shared componentNow go back to the
nuxt.config.ts
file to add your CSS. Your updated file should now be:// apps/web-1/nuxt.config.ts import tailwindcss from "@tailwindcss/vite"; // https://nuxt.com/docs/api/configuration/nuxt-config export default defineNuxtConfig({ compatibilityDate: '2025-05-15', devtools: { enabled: true }, css: ['~/assets/css/main.css'], vite: { plugins: [ tailwindcss(), ], }, })
To use the shared package in the nuxt app, you need to add the shared library. You can do this manually or using pnpm
pnpm add tailwind-config --filter web-1 --workspace
Now your package.json file is updated with the tailwind-config set up and should be something like this
// apps/web-1/package.json
{
"name": "nuxt-app",
"private": true,
"type": "module",
"scripts": {
"build": "nuxt build",
"dev": "nuxt dev",
"generate": "nuxt generate",
"preview": "nuxt preview",
"postinstall": "nuxt prepare"
},
"dependencies": {
"@tailwindcss/vite": "^4.1.7",
"nuxt": "^3.17.3",
"tailwind-config": "workspace:^",
"tailwindcss": "^4.1.7",
"vue": "^3.5.13",
"vue-router": "^4.5.1"
}
}
Testing shared tailwind configuration
Now that we are done with this setup, let’s add a simple customization to our tailwind and test that it works
Using @theme
from tailwind theme variable, let’s add new color variable
/* packages/tailwind-config/index.css */
@import "tailwindcss";
@theme {
--color-primary: pink;
--color-secondary: blue;
}
After modifying our tailwind configuration, all we have to do now is use it in the Nuxt app
Start the local server:
pnpm --filter web-1 dev
Result:
🎉 Congrats, we made it to the end!
You’ve just walked through how to set up TailwindCSS in a Nuxt-powered monorepo. High five for that! 🖐️
I know some parts might’ve felt like a whirlwind (pun intended), so if anything’s still a bit fuzzy, feel free to dive deeper into the official docs for clarity:
And yep — don’t forget, we’re using pnpm
workspaces to keep everything tidy and connected. Onward to building beautiful, scalable UIs! 💻✨
Github repo - https://github.com/Anumide/tailwind-v4-nuxt-monorepo
Subscribe to my newsletter
Read articles from Alaba Samuel Ayomide directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Alaba Samuel Ayomide
Alaba Samuel Ayomide
Passionate front-end developer with a strong zeal for Web development