Files
asepharyana-hub-guide/skills/monorepo/SKILL.md
T
asepharyana 5780d94ccf feat(hub-guide): language-agnostic auto-trigger across all skills
- Add principle 27: 'Language-Agnostic Auto-Trigger' to engineering-principles
- Remove hardcoded English-only keyword lists from all 26 skill descriptions
- Replace with concept-based detection: triggers from code context, project files,
  and file types regardless of spoken language
- Update detect-project.sh hook output with language-agnostic message
2026-07-25 12:59:43 +07:00

4.8 KiB

name, description
name description
monorepo Monorepo best practices — tooling, workspace configuration, shared dependencies, CI/CD, and dependency management. Use when working in monorepos (pnpm workspaces, moon, turborepo, Nx), managing shared packages. Triggers from project files and configuration, not just keyword matching."

Monorepo Best Practices

Tool Selection

Tool Best For Why
pnpm workspaces Package management Strict, fast, disk-efficient
moon Monorepo orchestration Task orchestration + caching
turborepo Task orchestration Simple caching, good for JS/TS
Nx Full monorepo framework Generators, dependency graph, affected commands
Git submodules Multi-repo coordination Separate repos imported together (this repo's pattern)

Workspace Structure (pnpm + moon)

├── apps/
│   ├── hub/            # Next.js app (submodule)
│   └── scraper/        # Rust API (submodule)
├── packages/           # Shared libraries (when not submodules)
├── infra/              # Shared infra config
├── pnpm-workspace.yaml
├── moon.yml
└── package.json

pnpm-workspace.yaml

packages:
  - 'apps/*'
  - 'packages/*'

moon.yml (root)

$schema: 'https://moonrepo.dev/schemas/project.json'
language: 'typescript'
type: 'application'

Shared Dependencies

# Install a shared dependency
pnpm add -w typescript

# Install in a specific package
pnpm add --filter @scope/package zod

# Run in all packages
pnpm -r run build

Rules:

  • One version of a dependency across the monorepo — use pnpm overrides or resolution.
  • Root devDependencies for shared tooling (TypeScript, Biome, ESLint).
  • Explicit dependencies — never rely on hoisting.
  • Lock file (pnpm-lock.yaml) committed — immutable installs.

Git Submodules (this repo's pattern)

asepharyana-hub/
├── apps/
│   ├── hub/          → asepharyana/asepharyana-hub-hub
│   └── scraper/      → asepharyana/asepharyana-hub-scraper

Submodule Workflow

# Init after clone
git submodule update --init --recursive

# Update all submodules to latest
git submodule foreach git pull origin main

# Update one submodule
cd apps/hub && git checkout main && git pull
cd ../.. && git add apps/hub && git commit -m "chore(deps): update hub submodule"
git push

State indicators:

  • (HEAD) — detached at committed pointer (normal state).
  • (main) — on a branch (you've done cd apps/name && git checkout main).
  • Dirty — uncommitted changes inside submodule.

When to Use Submodules vs Workspaces

Need Use
Independent repos, separate deploy Submodules
Shared code within one repo Workspaces
Tightly coupled, always deploy together Workspaces
Loosely coupled, different teams Submodules

CI/CD for Monorepos

Selective Builds

# Only run relevant workflows based on changed paths
on:
  push:
    branches: [main]
    paths:
      - 'apps/hub/**'
      - 'infra/docker/hub.Dockerfile'

Affected Commands (Nx/Turborepo/Moon)

moon ci               # Runs affected tasks based on changes
npx nx affected:test   # Nx style
turbo run build        # Turborepo — leverages cache

Caching

  • moon/turborepo cache task outputs by file hash + env.
  • pnpm caches node_modules.
  • Docker layer caching — Registry-based caching for Docker builds.

Shared Configuration

TypeScript

// tsconfig.base.json at root — extended by all packages
{
  "compilerOptions": {
    "strict": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true,
    "moduleResolution": "bundler"
  }
}

ESLint / Biome

// biome.json at root — shared config for all packages
{
  "formatter": { "indentStyle": "tab", "lineWidth": 120 },
  "linter": { "rules": { "recommended": true } }
}

Dependency Management

  • Dependabot / Renovate — automate dependency updates.
  • pnpm dedupe — deduplicate after updates.
  • Check for duplicatespnpm ls -r or pnpm why <package>.
  • When to upgrade:
    • Patch: auto-merge.
    • Minor: update weekly.
    • Major: scheduled migration, document breaking changes.

Anti-patterns

  • Different dependency versions across packages — inconsistent builds
  • Hoisting assumptions — code works in dev but not in CI because of missing deps
  • Monolithic package.json — each package declares its own dependencies
  • No .npmrc with shamefully-hoist=true — defeats pnpm's strictness
  • Circular dependencies between packages — extract shared code
  • Every change rebuilds everything — use affected commands and caching
  • Submodule pointer drift — always commit after updating submodules