Turborepo Monorepo Guide: Organize Your Frontend Projects at Scale
Turborepo's intelligent caching makes monorepos fast. Learn to set up a Turborepo workspace with shared packages, understand task graphs, and optimize CI build times.
Why Turborepo for Monorepos
A monorepo puts multiple projects in one repository — your app, a shared UI component library, utility packages, and internal tools. Without intelligent caching, every CI run rebuilds everything. Turborepo's content-aware caching means unchanged packages are never rebuilt — dramatically cutting CI times from 10+ minutes to under 2.
Initial Setup
npx create-turbo@latest my-monorepo
cd my-monorepo
This creates a workspace with example apps and packages. The structure:
my-monorepo/
apps/
web/ # Your Next.js app
docs/ # Documentation site
packages/
ui/ # Shared React components
config-ts/ # Shared tsconfig
config-eslint/ # Shared ESLint config
package.json # Root workspace config
turbo.json # Pipeline definition
pnpm-workspace.yaml
Defining the Pipeline in turbo.json
// turbo.json
{
"$schema": "https://turbo.build/schema.json",
"ui": "tui",
"tasks": {
"build": {
"dependsOn": ["^build"],
"inputs": ["$TURBO_DEFAULT$", ".env.local"],
"outputs": [".next/**", "!.next/cache/**", "dist/**"]
},
"test": {
"dependsOn": ["^build"],
"inputs": ["src/**", "tests/**", "vitest.config.*"]
},
"lint": {
"inputs": ["src/**", "*.json"]
},
"typecheck": {
"dependsOn": ["^build"]
},
"dev": {
"cache": false,
"persistent": true
}
}
}
Creating a Shared UI Package
// packages/ui/package.json
{
"name": "@repo/ui",
"version": "0.0.0",
"private": true,
"exports": {
".": "./src/index.ts",
"./button": "./src/button.tsx",
"./card": "./src/card.tsx"
},
"devDependencies": {
"@repo/config-ts": "workspace:*",
"typescript": "^5.4.2"
},
"peerDependencies": {
"react": "^19.0.0"
}
}
// packages/ui/src/button.tsx
import { type ButtonHTMLAttributes } from 'react';
interface ButtonProps extends ButtonHTMLAttributes<HTMLButtonElement> {
variant?: 'primary' | 'secondary' | 'ghost';
size?: 'sm' | 'md' | 'lg';
}
export function Button({ variant = 'primary', size = 'md', className = '', ...props }: ButtonProps) {
const variants = {
primary: 'bg-blue-600 text-white hover:bg-blue-700',
secondary: 'bg-gray-100 text-gray-900 hover:bg-gray-200',
ghost: 'hover:bg-gray-100 text-gray-700',
};
const sizes = { sm: 'px-3 py-1.5 text-sm', md: 'px-4 py-2', lg: 'px-6 py-3 text-lg' };
return (
<button
className={`rounded-lg font-medium transition-colors ${variants[variant]} ${sizes[size]} ${className}`}
{...props}
/>
);
}
Using the Shared Package in an App
// apps/web/package.json — add dependency
{
"dependencies": {
"@repo/ui": "workspace:*"
}
}
// apps/web/src/app/page.tsx
import { Button } from '@repo/ui/button';
export default function HomePage() {
return <Button variant="primary">Get Started</Button>;
}
Remote Caching for CI
# Connect to Vercel Remote Cache (free for personal use)
npx turbo login
npx turbo link
# CI workflow with cache
- run: pnpm turbo build --team=your-team
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: your-team
With remote caching, the second CI run of unchanged code completes in seconds rather than minutes — the cache is shared across all developers and CI machines.
Admin
Cal.com
Open source scheduling — tự host booking system, thay thế Calendly. Free & privacy-first.
Vercel
Deploy Next.js app trong 30 giây. Free tier rộng rãi cho side projects.
Bình luận (0)
Đăng nhập để bình luận
Chưa có bình luận nào. Hãy là người đầu tiên!