How to Set Up Shared Shadcn UI Components in an Nx Monorepo
Monorepos help teams scale applications efficiently, and Shadcn UI brings flexible, customizable UI components. In this article, I’ll show you how to set up shared Shadcn UI components inside an Nx monorepo so you can reuse them across multiple apps.
- April 27, 2025
- 04 min

Nx is a powerful open-source build system that provides tools and techniques for enhancing developer performance, optimizing CI performance, and maintaining code quality.
ShadCn is a collection of re-useable components that you can copy and paste. It provides beautifully designed components built with Radix UI and tailwindCSS. These components are both accessible and customizable, allowing you developers to easily integrate with projects. It’s open-source and free to use.
Prerequisite:
Before we begin, ensure you have the following installed:
Node.js and npm (Node Package Manager)
Next.js 13.4 or later
Nx
npm install --global nx@latest
Project setup
Let’s set up our monorepo and install the necessary dependencies.
- Create a new monorepo by running the following command:
npx create-nx-workspace@latest <project-name> packageManager=npm
Note: Create an empty monorepo that we will add other dependencies to.
Add nextJs to the repo
nx add @nx/nextCreate a nextjs application
nx g @nx/next:app apps/app-nameChoose tailwind for the style. and add `app routing` with the `src` folder (recommended)

Test the code
export default function Index() { return <h2 className="text-red-500 text-3xl text-center mt-10">Hello</h2>; }
run the application using this command:
npx nx run @my-org/web:dev
If you see this

Then Tailwind is fully setup and we are ready to continue.
- Create a shared package for the shared UI components by using the following command:
nx g @nx/next:lib shared

Install the following shadCn dependencies
npm install tailwindcss-animate class-variance-authority clsx tailwind-mergea. Configure path aliases by creating
tsconfig.jsona file to the root of the project://tsconfig.json { "compilerOptions": { "baseUrl": ".", "paths": { "@my-org/shared": ["shared/src/index.ts"], "@my-org/shared/*": ["shared/src/*"] } } }b. Create and Configure
components.jsonto the root of the project//components.josn { "$schema": "https://ui.shadcn.com/schema.json", "style": "new-york", "rsc": false, "tailwind": { "config": "apps/**/tailwind.config.js", "css": "apps/**/app/global.css", "baseColor": "stone", "cssVariables": true }, "aliases": { "components": "@my-org/shared/components", "utils": "@my-org/shared/shared/utils" } }c. inside your nextjs app folder, update the tailwind config file
const { join } = require('path'); const { createGlobPatternsForDependencies } = require('@nx/react/tailwind'); const { fontFamily } = require('tailwindcss/defaultTheme'); module.exports = { darkMode: ['class'], content: [ join( __dirname, '{src,pages,components,app}/**/*!(*.stories|*.spec).{ts,tsx,html}' ), // Explicitly include your shared library components join(__dirname, '../../shared/**/*.{js,ts,jsx,tsx}'), // Keep this for other dependencies ...createGlobPatternsForDependencies(__dirname), ], theme: { extend: { colors: { border: 'hsl(var(--border))', input: 'hsl(var(--input))', ring: 'hsl(var(--ring))', background: 'hsl(var(--background))', foreground: 'hsl(var(--foreground))', primary: { DEFAULT: 'hsl(var(--primary))', foreground: 'hsl(var(--primary-foreground))', }, secondary: { DEFAULT: 'hsl(var(--secondary))', foreground: 'hsl(var(--secondary-foreground))', }, destructive: { DEFAULT: 'hsl(var(--destructive))', foreground: 'hsl(var(--destructive-foreground))', }, muted: { DEFAULT: 'hsl(var(--muted))', foreground: 'hsl(var(--muted-foreground))', }, accent: { DEFAULT: 'hsl(var(--accent))', foreground: 'hsl(var(--accent-foreground))', }, popover: { DEFAULT: 'hsl(var(--popover))', foreground: 'hsl(var(--popover-foreground))', }, card: { DEFAULT: 'hsl(var(--card))', foreground: 'hsl(var(--card-foreground))', }, }, borderRadius: { lg: `var(--radius)`, md: `calc(var(--radius) - 2px)`, sm: 'calc(var(--radius) - 4px)', }, fontFamily: { sans: ['var(--font-sans)', ...fontFamily.sans], }, keyframes: { 'accordion-down': { from: { height: '0' }, to: { height: 'var(--radix-accordion-content-height)' }, }, 'accordion-up': { from: { height: 'var(--radix-accordion-content-height)' }, to: { height: '0' }, }, }, animation: { 'accordion-down': 'accordion-down 0.2s ease-out', 'accordion-up': 'accordion-up 0.2s ease-out', }, }, }, plugins: [require('tailwindcss-animate')], };d. Add the following CSS to each project
@tailwind base;
@tailwind components;
@tailwind utilities;
@layer base {
:root {
--background: 0 0% 100%;
--foreground: 222.2 84% 4.9%;
--card: 0 0% 100%;
--card-foreground: 222.2 84% 4.9%;
--popover: 0 0% 100%;
--popover-foreground: 222.2 84% 4.9%;
--primary: 221.2 83.2% 53.3%;
--primary-foreground: 210 40% 98%;
--secondary: 210 40% 96.1%;
--secondary-foreground: 222.2 47.4% 11.2%;
--muted: 210 40% 96.1%;
--muted-foreground: 215.4 16.3% 46.9%;
--accent: 210 40% 96.1%;
--accent-foreground: 222.2 47.4% 11.2%;
--destructive: 0 84.2% 60.2%;
--destructive-foreground: 210 40% 98%;
--border: 214.3 31.8% 91.4%;
--input: 214.3 31.8% 91.4%;
--ring: 221.2 83.2% 53.3%;
--radius: 0.5rem;
--chart-1: 12 76% 61%;
--chart-2: 173 58% 39%;
--chart-3: 197 37% 24%;
--chart-4: 43 74% 66%;
--chart-5: 27 87% 67%;
}
.dark {
--background: 222.2 84% 4.9%;
--foreground: 210 40% 98%;
--card: 222.2 84% 4.9%;
--card-foreground: 210 40% 98%;
--popover: 222.2 84% 4.9%;
--popover-foreground: 210 40% 98%;
--primary: 217.2 91.2% 59.8%;
--primary-foreground: 222.2 47.4% 11.2%;
--secondary: 217.2 32.6% 17.5%;
--secondary-foreground: 210 40% 98%;
--muted: 217.2 32.6% 17.5%;
--muted-foreground: 215 20.2% 65.1%;
--accent: 217.2 32.6% 17.5%;
--accent-foreground: 210 40% 98%;
--destructive: 0 62.8% 30.6%;
--destructive-foreground: 210 40% 98%;
--border: 217.2 32.6% 17.5%;
--input: 217.2 32.6% 17.5%;
--ring: 224.3 76.3% 48%;
--chart-1: 220 70% 50%;
--chart-2: 160 60% 45%;
--chart-3: 30 80% 55%;
--chart-4: 280 65% 60%;
--chart-5: 340 75% 55%;
}
}
@layer base {
* {
@apply border-border;
}
body {
@apply bg-background text-foreground;
font-feature-settings: "rlig" 1, "calt" 1;
}
}
e. Add a cn helper to the
shared/src/lib/utils.tsimport { clsx, type ClassValue } from 'clsx'; import { twMerge } from 'tailwind-merge'; export function cn(...inputs: ClassValue[]) { return twMerge(clsx(inputs)); }Create components using the shadCn command
npx shadcn@latest add button
A components folder will be generated inside our shared folder

Finally, let’s export our components from the shared package
//shared/src/index.ts
export * from './components/ui/button';
And Finally let’s use it
import { Button } from '@my-org/shared';
export default function Index() {
return (
<div className="flex justify-center flex-col w-[50%] m-20">
<Button variant={"destructive"}>Hello</Button>
</div>
);
}
And that’s it, Now we can create any shared UI components and use them as needed.