| name | monorepo-governance |
| description | Monorepo governance patterns from Nx, Turborepo, and Changesets. Task graph execution, affected-only CI, remote caching, module boundary enforcement, shared config packages, and coordinated versioning. Sources: nrwl/nx, vercel/turborepo, changesets/changesets, nicowillis/pkg-size, nicowillis/size-limit, nicowillis/wireit. |
/monorepo-governance
When to Use
- Setting up CI to only rebuild what changed
- Enforcing that packages don't import from sibling internals
- Coordinating version bumps across packages before publish
- "CI takes 20 min but only one package changed"
Do NOT use for
- Single-package repos
- Repos without package-level boundaries (flat source tree)
Affected-Only CI (Nx)
npx nx affected --target=test --base=origin/main --head=HEAD
npx turbo run test --filter="...[origin/main]"
Task Pipeline (Turborepo)
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"build": {
"dependsOn": ["^build"],
"inputs": ["src/**", "tsconfig.json"],
"outputs": ["dist/**"]
},
"test": {
"dependsOn": ["build"],
"cache": true
},
"lint": {
"cache": true
},
"dev": {
"cache": false,
"persistent": true
}
}
}
Module Boundary Enforcement (Nx)
{ "tags": ["scope:auth", "type:feature"] }
{ "tags": ["scope:shared", "type:util"] }
{
"rules": {
"@nx/enforce-module-boundaries": ["error", {
"depConstraints": [
{
"sourceTag": "scope:auth",
"onlyDependOnLibsWithTags": ["scope:shared", "scope:auth"]
},
{
"sourceTag": "type:feature",
"notDependOnLibsWithTags": [
Shared Config Packages
packages/
config-eslint/ ← shared ESLint config
index.js → module.exports = { extends: [...], rules: {...} }
config-typescript/ ← shared tsconfig
base.json → { "compilerOptions": { "strict": true, ... } }
config-jest/ ← shared Jest preset
jest.config.js → module.exports = { preset: 'ts-jest', ... }
// Each app/lib extends the shared config:
// .eslintrc.json: { "extends": ["@myrepo/config-eslint"] }
// tsconfig.json: { "extends": "@myrepo/config-typescript/base.json" }
Coordinated Versioning (Changesets)
npx changeset
npx changeset version
npx changeset publish
Remote Cache (Turborepo Cloud / Nx Cloud)
npx turbo link
npx nx connect
Anti-Fake-Pass Checklist
❌ CI runs all packages on every PR (affected detection not set up)
❌ Feature package importing from another feature package (boundary violation)
❌ turbo.json task has no "outputs" (outputs are never cached)
❌ Version bumps done manually without changesets (drift between packages)
❌ Shared tsconfig not extended — each package has divergent compiler options
❌ "dev" task marked cache: true (persistent tasks must be cache: false)