Monorepo Management
Seth HobsonCommunityCreated by Seth Hobson
- Skill
- Tool integration
- Software development
- MIT
- No issues found
AutoGineer summary
Written by AutoGineer from the skill’s own files, not by the author
This skill provides a comprehensive framework for managing monorepos, focusing on build optimization, dependency management, and code sharing. It covers the setup and configuration of industry-standard tools like Turborepo, Nx, and pnpm workspaces to ensure scalable development workflows. The guide addresses common challenges such as build performance, circular dependencies, and CI/CD complexity, offering best practices for maintaining consistent standards across multiple packages and applications.
What it does
- Guides the setup of monorepos using pnpm workspaces, Turborepo, or Nx.
- Provides configuration patterns for build systems to optimize task execution and caching.
- Demonstrates how to centralize shared configurations for TypeScript and ESLint.
- Outlines strategies for managing dependencies and avoiding common pitfalls like phantom dependencies.
- Explains how to implement CI/CD workflows for monorepo publishing and versioning.
- Offers techniques for visualizing dependency graphs and running affected project tasks.
When to use it
- When initiating a new project that requires multiple packages or applications in one repository.
- When migrating existing multi-repo projects into a unified monorepo structure.
- When build times or dependency management have become bottlenecks in a large project.
- When you need to enforce consistent tooling and code-sharing standards across teams.
- When setting up automated versioning and publishing for multiple packages.
Advantages
- Enables atomic commits and easier refactoring across the entire codebase.
- Improves build performance through intelligent caching and task orchestration.
- Simplifies dependency management by centralizing shared libraries and configurations.
- Provides better code visibility and consistent standards across projects.
- Supports scalable development by allowing targeted builds and tests for affected projects.
Usage examples
- “How do I set up a new monorepo using Turborepo and pnpm?”
- The agent provides the commands to initialize a Turborepo project and explains the necessary pnpm-workspace.yaml configuration for managing packages.
- “How can I optimize my build process in a large Nx monorepo?”
- The agent explains how to configure targetDefaults in nx.json and use affected commands to run only the necessary builds and tests.
- “What is the best way to share TypeScript configurations across my monorepo packages?”
- The agent demonstrates how to create a base tsconfig in a shared package and extend it in individual application configurations.
- “How do I publish multiple packages in my monorepo using Changesets?”
- The agent outlines the workflow for initializing Changesets, creating change records, and configuring the GitHub Action for automated publishing.
Install
Download the skill as a ZIP:
https://autogineer.com/agent-skills/wshobson/monorepo-management/downloadUnzip it into the cross-client skills folder of your project:
mkdir -p .agents/skills && unzip monorepo-management.zip -d .agents/skills
Documentation by Seth Hobson
Monorepo Management
Build efficient, scalable monorepos that enable code sharing, consistent tooling, and atomic changes across multiple packages and applications.
When to Use This Skill
Setting up new monorepo projects
Migrating from multi-repo to monorepo
Optimizing build and test performance
Managing shared dependencies
Implementing code sharing strategies
Setting up CI/CD for monorepos
Versioning and publishing packages
Debugging monorepo-specific issues
Core Concepts
1. Why Monorepos?
Advantages:
Shared code and dependencies
Atomic commits across projects
Consistent tooling and standards
Easier refactoring
Simplified dependency management
Better code visibility
Challenges:
Build performance at scale
CI/CD complexity
Access control
Large Git repository
2. Monorepo Tools
Package Managers:
pnpm workspaces (recommended)
npm workspaces
Yarn workspaces
Build Systems:
Turborepo (recommended for most)
Nx (feature-rich, complex)
Lerna (older, maintenance mode)
Turborepo Setup
Initial Setup
# Create new monorepo
npx create-turbo@latest my-monorepo
cd my-monorepo
# Structure:
# apps/
# web/ - Next.js app
# docs/ - Documentation site
# packages/
# ui/ - Shared UI components
# config/ - Shared configurations
# tsconfig/ - Shared TypeScript configs
# turbo.json - Turborepo configuration
# package.json - Root package.jsonConfiguration
// turbo.json
{
"$schema": "https://turbo.build/schema.json",
"globalDependencies": ["**/.env.*local"],
"tasks": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**", "!.next/cache/**"]
},
"test": {
"dependsOn": ["build"],
"outputs": ["coverage/**"]
},
"lint": {
"outputs": []
},
"dev": {
"cache": false,
"persistent": true
},
"type-check": {
"dependsOn": ["^build"],
"outputs": []
}
}
}// package.json (root)
{
"name": "my-monorepo",
"private": true,
"scripts": {
"build": "turbo run build",
"dev": "turbo run dev",
"test": "turbo run test",
"lint": "turbo run lint",
"format": "prettier --write \"**/*.{ts,tsx,md}\"",
"clean": "turbo run clean && rm -rf node_modules"
},
"devDependencies": {
"turbo": "^2.0.0",
"prettier": "^3.0.0",
"typescript": "^5.0.0"
},
"packageManager": "[email protected]"
}pnpm reads workspace packages only from pnpm-workspace.yaml, so declare them there (see references/details.md). Turborepo 2 renamed pipeline to tasks and rejects a turbo.json that still uses pipeline; run npx @turbo/codemod migrate to upgrade a 1.x config.
Package Structure
// packages/ui/package.json
{
"name": "@repo/ui",
"version": "0.0.0",
"private": true,
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"exports": {
".": {
"import": "./dist/index.js",
"types": "./dist/index.d.ts"
},
"./button": {
"import": "./dist/button.js",
"types": "./dist/button.d.ts"
}
},
"scripts": {
"build": "tsup src/index.ts --format esm,cjs --dts",
"dev": "tsup src/index.ts --format esm,cjs --dts --watch",
"lint": "eslint src/",
"type-check": "tsc --noEmit"
},
"devDependencies": {
"@repo/tsconfig": "workspace:*",
"tsup": "^7.0.0",
"typescript": "^5.0.0"
},
"dependencies": {
"react": "^18.2.0"
}
}Detailed patterns and worked examples
Detailed pattern documentation lives in references/details.md. Read that file when the navigation tier above is insufficient.
Best Practices
Consistent Versioning: Lock dependency versions across workspace
Shared Configs: Centralize ESLint, TypeScript, Prettier configs
Dependency Graph: Keep it acyclic, avoid circular dependencies
Cache Effectively: Configure inputs/outputs correctly
Type Safety: Share types between frontend/backend
Testing Strategy: Unit tests in packages, E2E in apps
Documentation: README in each package
Release Strategy: Use changesets for versioning
Common Pitfalls
Circular Dependencies: A depends on B, B depends on A
Phantom Dependencies: Using deps not in package.json
Incorrect Cache Inputs: Missing files in Turborepo inputs
Over-Sharing: Sharing code that should be separate
Under-Sharing: Duplicating code across packages
Large Monorepos: Without proper tooling, builds slow down
Publishing Packages
# Using Changesets
pnpm add -Dw @changesets/cli
pnpm changeset init
# Create changeset
pnpm changeset
# Version packages
pnpm changeset version
# Publish
pnpm changeset publish# .github/workflows/release.yml
- name: Create Release Pull Request or Publish
uses: changesets/action@v1
with:
publish: pnpm release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}Files
- ATTRIBUTION.mdAdded by AutoGineer997 B
- LICENSELicence file added by AutoGineer1.0 KiB
- SKILL.md5.3 KiB
- references/details.md7.6 KiB
references/details.md
monorepo-management — detailed patterns and worked examples
pnpm Workspaces
Setup
# pnpm-workspace.yaml
packages:
- "apps/*"
- "packages/*"
- "tools/*"// .npmrc
# Hoist shared dependencies
shamefully-hoist=true
# Strict peer dependencies
auto-install-peers=true
strict-peer-dependencies=true
# Performance
store-dir=~/.pnpm-storeDependency Management
# Install dependency in specific package
pnpm add react --filter @repo/ui
pnpm add -D typescript --filter @repo/ui
# Install workspace dependency
pnpm add @repo/ui --filter web
# Install in all packages
pnpm add -D eslint -w
# Update all dependencies
pnpm update -r
# Remove dependency
pnpm remove react --filter @repo/uiScripts
# Run script in specific package
pnpm --filter web dev
pnpm --filter @repo/ui build
# Run in all packages
pnpm -r build
pnpm -r test
# Run in parallel
pnpm -r --parallel dev
# Filter by pattern
pnpm --filter "@repo/*" build
pnpm --filter "...web" build # Build web and dependenciesNx Monorepo
Setup
# Create Nx monorepo
npx create-nx-workspace@latest my-org
# Generate applications
nx generate @nx/react:app my-app
nx generate @nx/next:app my-next-app
# Generate libraries
nx generate @nx/react:lib ui-components
nx generate @nx/js:lib utilsConfiguration
// nx.json
{
"extends": "nx/presets/npm.json",
"$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", "{workspaceRoot}/.eslintrc.json"],
"cache": true
}
},
"namedInputs": {
"default": ["{projectRoot}/**/*", "sharedGlobals"],
"production": [
"default",
"!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)",
"!{projectRoot}/tsconfig.spec.json"
],
"sharedGlobals": []
}
}Running Tasks
# Run task for specific project
nx build my-app
nx test ui-components
nx lint utils
# Run for affected projects
nx affected:build
nx affected:test --base=main
# Visualize dependencies
nx graph
# Run in parallel
nx run-many --target=build --all --parallel=3Shared Configurations
TypeScript Configuration
// packages/tsconfig/base.json
{
"compilerOptions": {
"strict": true,
"esModuleInterop": true,
"skipLibCheck": true,
"forceConsistentCasingInFileNames": true,
"module": "ESNext",
"moduleResolution": "bundler",
"resolveJsonModule": true,
"isolatedModules": true,
"incremental": true,
"declaration": true
},
"exclude": ["node_modules"]
}
// packages/tsconfig/react.json
{
"extends": "./base.json",
"compilerOptions": {
"jsx": "react-jsx",
"lib": ["ES2022", "DOM", "DOM.Iterable"]
}
}
// apps/web/tsconfig.json
{
"extends": "@repo/tsconfig/react.json",
"compilerOptions": {
"outDir": "dist",
"rootDir": "src"
},
"include": ["src"],
"exclude": ["node_modules", "dist"]
}ESLint Configuration
// packages/config/eslint-preset.js
module.exports = {
extends: [
"eslint:recommended",
"plugin:@typescript-eslint/recommended",
"plugin:react/recommended",
"plugin:react-hooks/recommended",
"prettier",
],
plugins: ["@typescript-eslint", "react", "react-hooks"],
parser: "@typescript-eslint/parser",
parserOptions: {
ecmaVersion: 2022,
sourceType: "module",
ecmaFeatures: {
jsx: true,
},
},
settings: {
react: {
version: "detect",
},
},
rules: {
"@typescript-eslint/no-unused-vars": "error",
"react/react-in-jsx-scope": "off",
},
};
// apps/web/.eslintrc.js
module.exports = {
extends: ["@repo/config/eslint-preset"],
rules: {
// App-specific rules
},
};Code Sharing Patterns
Pattern 1: Shared UI Components
// packages/ui/src/button.tsx
import * as React from 'react';
export interface ButtonProps {
variant?: 'primary' | 'secondary';
children: React.ReactNode;
onClick?: () => void;
}
export function Button({ variant = 'primary', children, onClick }: ButtonProps) {
return (
<button
className={`btn btn-${variant}`}
onClick={onClick}
>
{children}
</button>
);
}
// packages/ui/src/index.ts
export { Button, type ButtonProps } from './button';
export { Input, type InputProps } from './input';
// apps/web/src/app.tsx
import { Button } from '@repo/ui';
export function App() {
return <Button variant="primary">Click me</Button>;
}Pattern 2: Shared Utilities
// packages/utils/src/string.ts
export function capitalize(str: string): string {
return str.charAt(0).toUpperCase() + str.slice(1);
}
export function truncate(str: string, length: number): string {
return str.length > length ? str.slice(0, length) + "..." : str;
}
// packages/utils/src/index.ts
export * from "./string";
export * from "./array";
export * from "./date";
// Usage in apps
import { capitalize, truncate } from "@repo/utils";Pattern 3: Shared Types
// packages/types/src/user.ts
export interface User {
id: string;
email: string;
name: string;
role: "admin" | "user";
}
export interface CreateUserInput {
email: string;
name: string;
password: string;
}
// Used in both frontend and backend
import type { User, CreateUserInput } from "@repo/types";Build Optimization
Turborepo Caching
// turbo.json
{
"tasks": {
"build": {
// Build depends on dependencies being built first
"dependsOn": ["^build"],
// Cache these outputs
"outputs": ["dist/**", ".next/**"],
// Cache based on these inputs (default: all files)
"inputs": ["src/**/*.tsx", "src/**/*.ts", "package.json"]
},
"test": {
// Run tests in parallel, don't depend on build
"cache": true,
"outputs": ["coverage/**"]
}
}
}Remote Caching
# Turborepo Remote Cache (Vercel)
npx turbo login
npx turbo link
# Custom remote cache
# turbo.json
{
"remoteCache": {
"signature": true,
"enabled": true
}
}CI/CD for Monorepos
GitHub Actions
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
with:
fetch-depth: 0 # For Nx affected commands
- uses: pnpm/action-setup@v2
with:
version: 8
- uses: actions/setup-node@v3
with:
node-version: 18
cache: "pnpm"
- name: Install dependencies
run: pnpm install --frozen-lockfile
- name: Build
run: pnpm turbo run build
- name: Test
run: pnpm turbo run test
- name: Lint
run: pnpm turbo run lint
- name: Type check
run: pnpm turbo run type-checkDeploy Affected Only
The step below uses Nx to check whether web changed, then runs the deploy script in apps/web/package.json. The create-turbo starter has neither, so add Nx (npx nx@latest init) and a deploy script for your hosting provider first.
# Deploy only changed apps
- name: Deploy affected apps
run: |
if pnpm nx show projects --affected --base=origin/main --head=HEAD | grep -qx "web"; then
echo "Deploying web app"
# `pnpm deploy` is a built-in command; use `run` for the package's deploy script
pnpm --filter web run deploy
fiRequirements and compatibility
Works with: Claude Code, Claude apps, OpenAI Codex, GitHub Copilot, Cursor, Gemini CLI, Kiro, OpenCode, Goose, Amp, Roo Code, JetBrains Junie, Factory Droid, Devin (ex-Windsurf), Mistral Vibe, OpenHands, Letta
“Works with” means the tool reads the open Agent Skills format; a skill written for one tool may use features others lack.
Needs: Needs Node.js
Security
No issues found by our static scan· No issues found
A static scan is not a guarantee. Skills are third-party content: review a skill before you let an agent use it.
Attribution and licence
- Created by
- Seth Hobson
- Publisher
- Seth Hobson (Community)
- Source
- wshobson/agents · plugins/developer-essentials/skills/monorepo-management · commit 4bde316
- Licence
- MIT License (redistribution allowed)
- LICENSE (added by AutoGineer from LICENSE)
- ATTRIBUTION.md (written by AutoGineer)
- Synced
AutoGineer is not affiliated with or endorsed by Seth Hobson or Seth Hobson.
Download ZIP
The ZIP holds the skill’s files, its licence files and an ATTRIBUTION.md. Download monorepo-management.zip