Monorepo Architecture with Turborepo: Scaling Frontend Projects
Turborepo makes monorepos fast with intelligent caching and parallel execution.
Project Setup
npx create-turbo@latest my-monorepo
cd my-monorepo
my-monorepo/
├── apps/
│ ├── web/ # Next.js app
│ ├── admin/ # Admin dashboard
│ └── api/ # NestJS API
├── packages/
│ ├── ui/ # Shared component library
│ ├── utils/ # Shared utilities
│ ├── config/ # Shared configs (ESLint, TypeScript)
│ └── types/ # Shared TypeScript types
├── turbo.json
└── package.json
turbo.json Configuration
{
"$schema": "https://turborepo.com/schema.json",
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "dist/**"],
"cache": true
},
"test": {
"dependsOn": ["build"],
"outputs": ["coverage/**"],
"cache": true
},
"lint": {
"outputs": [],
"cache": true
},
"dev": {
"cache": false,
"persistent": true
},
"typecheck": {
"dependsOn": ["^build"],
"cache": true
}
}
}
Shared UI Package
// packages/ui/src/Button.tsx
import * as React from 'react';
export interface ButtonProps {
variant?: 'primary' | 'secondary';
size?: 'sm' | 'md' | 'lg';
children: React.ReactNode;
onClick?: () => void;
}
export const Button: React.FC<ButtonProps> = ({
variant = 'primary',
size = 'md',
children,
onClick
}) => (
<button
className={`btn btn-${variant} btn-${size}`}
onClick={onClick}
>
{children}
</button>
);
// packages/ui/package.json
{
"name": "@myrepo/ui",
"exports": {
".": "./src/index.ts"
},
"devDependencies": {
"typescript": "^5.0.0",
"@myrepo/config": "*"
}
}
Shared TypeScript Config
// packages/config/tsconfig/base.json
{
"compilerOptions": {
"target": "ES2022",
"lib": ["ES2022"],
"module": "NodeNext",
"moduleResolution": "NodeNext",
"strict": true,
"skipLibCheck": true,
"noEmit": true
}
}
// packages/config/tsconfig/react.json
{
"extends": "./base.json",
"compilerOptions": {
"jsx": "react-jsx",
"lib": ["ES2022", "DOM"]
}
}
Remote Caching
# Login to Vercel Remote Cache
npx turbo login
# Link to Vercel
npx turbo link
# CI configuration
# turbo.json automatically uses remote cache
TURBO_TOKEN=${{ secrets.TURBO_TOKEN }}
TURBO_TEAM=${{ secrets.TURBO_TEAM }}
Running Tasks
# Build everything
turbo build
# Build specific app and its dependencies
turbo build --filter=web
# Build changed packages only
turbo build --filter="[main]"
# Run tests in parallel
turbo test
# Run dev for all apps
turbo dev
Turborepo's caching can reduce CI build times by 70-80% in large monorepos.