| name | monorepo-management |
| description | Enterprise monorepo patterns with Turborepo and Nx including task orchestration, caching, and CI/CD optimization |
| category | devops |
| triggers | ["monorepo","turborepo","nx","workspace","task orchestration","build caching"] |
Monorepo Management
Master monorepo architecture with Turborepo and Nx. This skill covers workspace configuration, task orchestration, caching strategies, and CI/CD optimization for large-scale codebases.
Purpose
Manage complex multi-package codebases efficiently:
- Configure workspace tooling and dependencies
- Orchestrate builds with optimal task scheduling
- Implement remote caching for faster builds
- Optimize CI/CD for affected packages only
- Share code and configurations across packages
- Scale to hundreds of packages
Features
1. Turborepo Setup
{
"$schema": "https://turbo.build/schema.json",
"globalDependencies": [".env", "tsconfig.base.json"],
"globalEnv": ["NODE_ENV", "CI"],
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**", "build/**"],
"env": ["NODE_ENV"]
},
"test": {
"dependsOn": ["build"],
"outputs": ["coverage/**"],
"inputs": ["src/**/*.ts", "src/**/*.tsx", "tests/**"]
},
"lint": {
"outputs": []
},
"dev": {
"cache": false,
"persistent": true
},
"type-check": {
"dependsOn": ["^build"],
"outputs": []
},
"clean": {
"cache": false
}
}
}
# Project structure
my-monorepo/
├── apps/
│ ├── web/ # Next.js frontend
│ │ ├── package.json
│ │ └── ...
│ ├── api/ # Express backend
│ │ ├── package.json
│ │ └── ...
│ └── mobile/ # React Native app
│ ├── package.json
│ └── ...
├── packages/
│ ├── ui/ # Shared component library
│ │ ├── package.json
│ │ └── ...
│ ├── config/ # Shared configs
│ │ ├── eslint/
│ │ ├── typescript/
│ │ └── tailwind/
│ ├── database/ # Prisma schema & client
│ │ ├── package.json
│ │ └── ...
│ └── utils/ # Shared utilities
│ ├── package.json
│ └── ...
├── turbo.json
├── package.json
└── pnpm-workspace.yaml
packages:
- "apps/*"
- "packages/*"
2. Nx Configuration
{
"$schema": "./node_modules/nx/schemas/nx-schema.json",
"targetDefaults": {
"build": {
"dependsOn": ["^build"],
"inputs": ["production", "^production"],
"cache": true
},
"test": {
"inputs": ["default", "^production", "{workspaceRoot}/jest.preset.js"],
"cache": true
},
"lint": {
"inputs": ["default"
{
"name": "web",
"$schema": "../../node_modules/nx/schemas/project-schema.json",
"projectType": "application",
"sourceRoot": "apps/web/src",
"targets": {
"build": {
"executor": "@nx/next:build",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/apps/web"
},
"configurations": {
"production": {
"outputPath": "dist/apps/web"
}
}
},
3. Task Orchestration
import { execSync, spawn } from 'child_process';
interface TaskConfig {
name: string;
command: string;
dependsOn?: string[];
parallel?: boolean;
cwd?: string;
}
function topologicalSort(tasks: Map<string, TaskConfig>): string[] {
const visited = new Set<string>();
const result: string[] = [];
function visit(name: string) {
if (visited.has(name)) return;
visited.add(name);
const task = tasks.get(name);
if (task?.dependsOn) {
for (const dep of task.dependsOn) {
visit(dep);
}
}
result.push(name);
}
for ( name tasks.()) {
(name);
}
result;
}
(): <> {
sorted = (tasks);
filtered = sorted.( taskNames.(t) || taskNames. === );
running = <, <>>();
completed = <>();
( name filtered) {
task = tasks.(name)!;
(task.) {
.(
task.
.( running.(dep))
.( running.(dep))
);
}
(running. >= concurrency) {
.(running.());
}
promise = (task).( {
completed.(name);
running.(name);
});
running.(name, promise);
}
.(running.());
}
(): <> {
.();
startTime = .();
( {
proc = (, [, task.], {
: task. || process.(),
: ,
});
proc.(, {
duration = ((.() - startTime) / ).();
(code === ) {
.();
();
} {
.();
( ());
}
});
});
}
4. Remote Caching
{
"remoteCache": {
"signature": true
}
}
{
"teamId": "team_xxx",
"apiUrl": "https://cache.example.com"
}
import express from 'express';
import { createHash } from 'crypto';
import { S3Client, PutObjectCommand, GetObjectCommand } from '@aws-sdk/client-s3';
const app = express();
const s3 = new S3Client({ region: process.env.AWS_REGION });
app.put('/v8/artifacts/:hash', async (req, res) => {
const { hash } = req.params;
const teamId = req.headers['x-artifact-client-ci'];
const chunks: Buffer[] = [];
for await ( chunk req) {
chunks.(chunk);
}
body = .(chunks);
s3.( ({
: process..,
: ,
: body,
}));
res.().({ : });
});
app.(, (req, res) => {
{ hash } = req.;
teamId = req.[];
{
response = s3.( ({
: process..,
: ,
}));
res.(, );
response.?.(res);
} {
res.().({ : });
}
});
app.();
5. CI/CD Optimization
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: ${{ vars.TURBO_TEAM }}
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: pnpm/action-setup@v2
with:
version: 8
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'pnpm'
- name: Install dependencies
run: pnpm install --frozen-lockfile
6. Shared Configurations
module.exports = {
extends: [
'eslint:recommended',
'plugin:@typescript-eslint/recommended',
'prettier',
],
parser: '@typescript-eslint/parser',
plugins: ['@typescript-eslint'],
rules: {
'@typescript-eslint/no-unused-vars': ['error', { argsIgnorePattern: '^_' }],
'@typescript-eslint/explicit-function-return-type': 'off',
},
ignorePatterns: ['dist', 'node_modules', '.turbo'],
};
module.exports = {
extends: [
'./index.js',
'plugin:react/recommended',
'plugin:react-hooks/recommended',
],
plugins: ['react', 'react-hooks'],
settings: {
react: { version: 'detect' },
},
rules: {
'react/react-in-jsx-scope': 'off',
'react/prop-types': 'off',
},
};
{
"$schema": "https://json.schemastore.org/tsconfig",
"compilerOptions": {
"target": "ES2022",
: [],
: ,
: ,
: ,
: ,
: ,
: ,
: ,
: ,
: ,
: ,
:
},
: [, ]
}
{
: ,
: ,
: {
: [, , ],
:
}
}
Use Cases
1. Multi-App Platform
# Build and deploy specific apps
pnpm turbo build --filter=web --filter=api
# Run dev for specific app with dependencies
pnpm turbo dev --filter=web...
# Test only affected by changes
pnpm turbo test --filter='...[HEAD~1]'
2. Component Library Publishing
{
"name": "@myorg/ui",
"version": "1.0.0",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.js"
},
"./styles.css": "./dist/styles.css"
},
"scripts": {
"build": "tsup src/index.ts --format cjs,esm --dts",
"dev": "tsup src/index.ts --format cjs,esm --dts --watch"
}
}
Best Practices
Do's
- Use remote caching - Dramatically speeds up CI
- Define clear package boundaries - Single responsibility
- Run affected only - Don't rebuild unchanged packages
- Share configurations - Consistent tooling
- Use workspace protocol -
workspace:* for internal deps
- Document dependency graph - Keep architecture clear
Don'ts
- Don't create circular dependencies
- Don't skip input/output definitions
- Don't ignore cache invalidation
- Don't duplicate configurations
- Don't over-share packages
- Don't skip CI optimization
Related Skills
- github-actions - CI/CD pipelines
- docker - Containerization
- typescript - Type-safe development
Reference Resources