Create Turborepo with NextJS, Tailwind v4 and Shadcn (React 19)

What is Turborepo ? Turborepo, developed by Vercel, is a powerful build system tool for JavaScript and TypeScript codebases that makes managing monorepos easier by optimizing workflows, speeding up build times, and ensuring consistency across projects. Key features of Turborepo Incremental Caching: Avoids rebuilding unchanged code, significantly improving build times. Parallel Execution: Runs tasks across multiple projects simultaneously. Remote Caching: Speeds up CI/CD pipelines by reusing cached results across different environments Efficient Dependency Management: Uses a single package.json or workspace approach to manage dependencies. Setting Up a Turborepo Project Step 1. Initialize a New Monorepo npx create-turbo@latest my-turborepo cd my-turborepo This starter repository includes Two deployable NextJS applications in apps folder Three packages libraries for use in the rest of the monorepo my-turborepo/ ├── apps/ │ ├── web/ # First Next.js application │ │ ├── app/ # Core directory for App Router │ │ │ ├── globals.css # Global styles │ │ │ ├── layout.tsx # Root layout component │ │ │ └── page.tsx # Home page component ("/") │ │ ├── public/ # Static assets (images, fonts, etc.) │ │ ├── next.config.js # Next.js configuration file │ │ ├── tsconfig.json # TypeScript configuration │ │ └── package.json # Project dependencies and scripts │ └── docs/ # Second Next.js application │ ├── app/ # Core directory for App Router │ │ ├── globals.css # Global styles │ │ ├── layout.tsx # Root layout component │ │ └── page.tsx # Home page component ("/") │ ├── public/ # Static assets (images, fonts, etc.) │ ├── next.config.js # Next.js configuration file │ ├── tsconfig.json # TypeScript configuration │ └── package.json # Project dependencies and scripts ├── packages/ # Shared packages │ ├── ui/ # Shared UI components │ │ ├── button.tsx # Example shared button component │ │ ├── input.tsx # Example shared input component │ │ └── package.json # Package dependencies and scripts │ └── eslint-config-custom/ # Shared ESLint configuration │ ├── index.js # ESLint configuration │ └── package.json # Package dependencies and scripts ├── turbo.json # Turborepo configuration ├── package.json # Root package dependencies and scripts └── pnpm-workspace.yaml # pnpm workspaces configuration Step 2. Installing turbo globally pnpm install turbo --global Step 3. Installing and setting up Tailwindcss V4 in UI package cd packages/ui pnpm install tailwindcss @tailwindcss/postcss postcss Once Tailwindcss and postcss plugin is installed, create a postcss.config.mjs file and add the following const config = { plugins: ["@tailwindcss/postcss"], }; export default config; Create default.css inside src/styles folder of ui package and add the following @import "tailwindcss"; Create an export alias for default.css and postcss.config.mjs in packages.json { "name": "@repo/ui", "version": "0.0.0", "private": true, "exports": { "./postcss.config": "./postcss.config.mjs", "./styles/*": "./src/styles/*" }, "scripts": { "lint": "eslint . --max-warnings 0", "generate:component": "turbo gen react-component", "check-types": "tsc --noEmit" }, "devDependencies": { "@repo/eslint-config": "workspace:*", "@repo/typescript-config": "workspace:*", "@tailwindcss/postcss": "^4.0.15", "@turbo/gen": "^2.4.4", "@types/node": "^22.13.10", "@types/react": "19.0.10", "@types/react-dom": "19.0.4", "eslint": "^9.22.0", "tailwindcss": "^4.0.15", "typescript": "5.8.2" }, "dependencies": { "react": "^19.0.0", "react-dom": "^19.0.0", } } Step 4. Using Tailwindcss V4 in Nextjs apps Install Tailwindcss v4 and postcss in your NextJs apps pnpm install tailwindcss @tailwindcss/postcss postcss then create a postcss.config.mjs file //using the config exported from packages/ui export { default } from "@repo/ui/postcss.config"; Find globals.css in your Nextjs app and add the following @import "tailwindcss"; @import "@repo/ui/styles/default.css"; @source '../../../packages/ui'; Don’t forget to add @repo/ui as dependency in package.json "dependencies": { "@repo/ui": "workspace:*", }, Note: Since i am using pnpm package manage i had to add "@repo/ui": "workspace:*" , if you are using yarn or npm add the package dependency "@repo/ui": "*" Verify if its working Step 5. Adding Shadcn ui cd packages/ui pnpm add class-variance-authority clsx tailwind-merge lucide-react tw-animate-css Create components.json file in packages/ui add the following {

Mar 28, 2025 - 17:40
 0
Create Turborepo with NextJS, Tailwind v4 and Shadcn (React 19)

What is Turborepo ?

Turborepo, developed by Vercel, is a powerful build system tool for JavaScript and TypeScript codebases that makes managing monorepos easier by optimizing workflows, speeding up build times, and ensuring consistency across projects.

Key features of Turborepo

  • Incremental Caching: Avoids rebuilding unchanged code, significantly improving build times.
  • Parallel Execution: Runs tasks across multiple projects simultaneously.
  • Remote Caching: Speeds up CI/CD pipelines by reusing cached results across different environments
  • Efficient Dependency Management: Uses a single package.json or workspace approach to manage dependencies.

Setting Up a Turborepo Project

Step 1. Initialize a New Monorepo

npx create-turbo@latest my-turborepo
cd my-turborepo

This starter repository includes

  • Two deployable NextJS applications in apps folder
  • Three packages libraries for use in the rest of the monorepo
my-turborepo/
├── apps/
│   ├── web/                # First Next.js application
│   │   ├── app/            # Core directory for App Router
│   │   │   ├── globals.css # Global styles
│   │   │   ├── layout.tsx  # Root layout component
│   │   │   └── page.tsx    # Home page component ("/")
│   │   ├── public/         # Static assets (images, fonts, etc.)
│   │   ├── next.config.js  # Next.js configuration file
│   │   ├── tsconfig.json   # TypeScript configuration
│   │   └── package.json    # Project dependencies and scripts
│   └── docs/               # Second Next.js application
│       ├── app/            # Core directory for App Router
│       │   ├── globals.css # Global styles
│       │   ├── layout.tsx  # Root layout component
│       │   └── page.tsx    # Home page component ("/")
│       ├── public/         # Static assets (images, fonts, etc.)
│       ├── next.config.js  # Next.js configuration file
│       ├── tsconfig.json   # TypeScript configuration
│       └── package.json    # Project dependencies and scripts
├── packages/               # Shared packages
│   ├── ui/                 # Shared UI components
│   │   ├── button.tsx      # Example shared button component
│   │   ├── input.tsx       # Example shared input component
│   │   └── package.json    # Package dependencies and scripts
│   └── eslint-config-custom/ # Shared ESLint configuration
│       ├── index.js        # ESLint configuration
│       └── package.json    # Package dependencies and scripts
├── turbo.json              # Turborepo configuration
├── package.json            # Root package dependencies and scripts
└── pnpm-workspace.yaml     # pnpm workspaces configuration

Step 2. Installing turbo globally

pnpm install turbo --global

Step 3. Installing and setting up Tailwindcss V4 in UI package

cd packages/ui
pnpm install tailwindcss @tailwindcss/postcss postcss

Once Tailwindcss and postcss plugin is installed, create a postcss.config.mjs file and add the following

const config = {
  plugins: ["@tailwindcss/postcss"],
};

export default config;

Create default.css inside src/styles folder of ui package and add the following

@import "tailwindcss";

Create an export alias for default.css and postcss.config.mjs in packages.json

{
  "name": "@repo/ui",
  "version": "0.0.0",
  "private": true,
  "exports": {
    "./postcss.config": "./postcss.config.mjs",
    "./styles/*": "./src/styles/*"
  },
  "scripts": {
    "lint": "eslint . --max-warnings 0",
    "generate:component": "turbo gen react-component",
    "check-types": "tsc --noEmit"
  },
  "devDependencies": {
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@tailwindcss/postcss": "^4.0.15",
    "@turbo/gen": "^2.4.4",
    "@types/node": "^22.13.10",
    "@types/react": "19.0.10",
    "@types/react-dom": "19.0.4",
    "eslint": "^9.22.0",
    "tailwindcss": "^4.0.15",
    "typescript": "5.8.2"
  },
  "dependencies": {
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
  }
}

Step 4. Using Tailwindcss V4 in Nextjs apps
Install Tailwindcss v4 and postcss in your NextJs apps

pnpm install tailwindcss @tailwindcss/postcss postcss

then create a postcss.config.mjs file

//using the config exported from packages/ui
export { default } from "@repo/ui/postcss.config"; 

Find globals.css in your Nextjs app and add the following

@import "tailwindcss";
@import "@repo/ui/styles/default.css";

@source '../../../packages/ui';

Don’t forget to add @repo/ui as dependency in package.json

  "dependencies": {
    "@repo/ui": "workspace:*",
  },

Note: Since i am using pnpm package manage i had to add "@repo/ui": "workspace:*" , if you are using yarn or npm add the package dependency "@repo/ui": "*"

Verify if its working
Image description

Step 5. Adding Shadcn ui

cd packages/ui
pnpm add class-variance-authority clsx tailwind-merge lucide-react tw-animate-css

Create components.json file in packages/ui add the following

{
  "$schema": "https://ui.shadcn.com/schema.json",
  "style": "new-york",
  "rsc": true,
  "tsx": true,
  "tailwind": {
    "config": "",
    "css": "src/styles/default.css",
    "baseColor": "zinc",
    "cssVariables": true
  },
  "iconLibrary": "lucide",
  "aliases": {
    "components": "@repo/ui/components",
    "ui": "@repo/ui/components/shadcn"
    "utils": "@repo/ui/lib/utils",
    "lib": "@repo/ui/lib",
    "hooks": "@repo/ui/hooks"
  }
}

Configure the path aliases in your packages/ui/tsconfig.json file.

{
  "extends": "@repo/typescript-config/react-library.json",
  "compilerOptions": {
    "baseUrl": ".",
    "paths": {
      "@repo/ui/*": ["./src/*"],
    }
  },
  "include": ["src"],
  "exclude": ["node_modules"]
}

Create lib/utils.ts file in packages/ui/src and add the following

import { clsx, type ClassValue } from "clsx";
import { twMerge } from "tailwind-merge";

export function cn(...inputs: ClassValue[]) {
  return twMerge(clsx(inputs));
}

Now you can install Shadcn components using shadcn CLI, let try it out

npx shadcn@latest add button

This will install the button component in packages/ui/src/components/shadcn
Image description

To use the components you need add a path alias in exportsin package.json

{
  "name": "@repo/ui",
  "version": "0.0.0",
  "private": true,
  "exports": {
    "./*": "./src/*.tsx",
    "./lib/utils": "./src/lib/utils.ts",
    "./postcss.config": "./postcss.config.mjs",
    "./styles/*": "./src/styles/*",
  },
  "peerDependencies": {
    "react": "^19.0.0",
    "react-dom": "^19.0.0"
  },
  "scripts": {
    "lint": "eslint . --max-warnings 0",
    "generate:component": "turbo gen react-component",
    "check-types": "tsc --noEmit"
  },
  "devDependencies": {
    "@repo/eslint-config": "workspace:*",
    "@repo/typescript-config": "workspace:*",
    "@tailwindcss/postcss": "^4.0.15",
    "@turbo/gen": "^2.4.4",
    "@types/node": "^22.13.10",
    "@types/react": "19.0.10",
    "@types/react-dom": "19.0.4",
    "eslint": "^9.22.0",
    "tailwindcss": "^4.0.15",
    "typescript": "5.8.2"
  },
  "dependencies": {
    "@radix-ui/react-slot": "^1.1.2",
    "class-variance-authority": "^0.7.1",
    "clsx": "^2.1.1",
    "lucide-react": "^0.483.0",
    "react": "^19.0.0",
    "react-dom": "^19.0.0",
    "tailwind-merge": "^3.0.2",
    "tw-animate-css": "^1.2.4"
  }
}

Now you can use the shadcn components in your nextjs applications

//page.tsx

import { Button } from "@repo/ui/components/shadcn/button";

const Home = () => {
  return (
    
); }; export default Home;

Conclusion

Monorepos offer a powerful way to manage multiple projects under a single repository, but they can introduce challenges in scalability and performance. Turborepo solves these issues by providing a high-performance build system that optimizes dependency management and execution.

By following best practices and leveraging Turborepo’s caching and parallel execution, you can efficiently manage your monorepo projects.