Skip to content
Back to skills

Monorepo Config

ASecurity

Monorepo configuration — shared configs, package publishing, internal packages, versioning strategies, Git optimization (sparse checkout, worktrees, LFS)

  • 2 stars
  • 0 votes
  • 0 copies
  • 1 view
  • Added October 26, 2026
developmentjavascripttypescriptgojavabashreactnextjsnodegitapi

Works with

  • cli
  • api

Security analysis

A96/100
  • mediumInstalls packages at runtime which could introduce malicious dependencies

Pro shows the line behind each finding and how to fix it

Scanned October 26, 2026

npx -y skills add nhan03bit/ultrathink --skill monorepo-config --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Monorepo Config?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Monorepo Config
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/nhan03bit-monorepo-config/badge)](https://www.skillsdirectory.com/skills/nhan03bit-monorepo-config)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: monorepo-config
description: Monorepo configuration — shared configs, package publishing, internal packages, versioning strategies, Git optimization (sparse checkout, worktrees, LFS)
layer: domain
category: build-tools
triggers:
  - "shared config"
  - "internal package"
  - "package publishing"
  - "monorepo config"
  - "workspace config"
  - "changesets"
  - "git monorepo"
  - "sparse checkout"
  - "git worktree"
  - "shallow clone"
  - "large repo"
  - "git lfs"
  - "monorepo"
inputs:
  - "Monorepo structure and workspace setup needs"
  - "Shared configuration requirements across packages"
  - "Package publishing and versioning workflows"
  - "Internal package dependency management"
outputs:
  - "Workspace configuration files"
  - "Shared config packages (ESLint, TypeScript, Tailwind)"
  - "Changesets versioning setup"
  - "Internal package build and linking strategies"
linksTo:
  - turborepo
  - pnpm
  - nx
  - git-workflow
linkedFrom: []
preferredNextSkills:
  - turborepo
  - pnpm
fallbackSkills:
  - monorepo
riskLevel: low
memoryReadPolicy: selective
memoryWritePolicy: none
sideEffects: []
---

# Monorepo Configuration

## Purpose

Provide expert guidance on configuring monorepo workspaces with shared configs, internal packages, package publishing pipelines, and versioning strategies. Covers pnpm workspaces, Turborepo integration, shared configuration packages, and Changesets for automated versioning and publishing.

## Key Patterns

### Workspace Structure

Standard monorepo layout with pnpm workspaces:

```
monorepo/
  package.json            # Root package.json
  pnpm-workspace.yaml     # Workspace definition
  turbo.json              # Turborepo pipeline config
  .changeset/             # Changesets config
    config.json
  packages/
    config-eslint/        # Shared ESLint config
    config-typescript/    # Shared TypeScript config
    config-tailwind/      # Shared Tailwind config
    ui/                   # Shared UI component library
    utils/                # Shared utilities
  apps/
    web/                  # Next.js web app
    api/                  # API server
    docs/                 # Documentation site
```

**pnpm-workspace.yaml:**

```yaml
packages:
  - "apps/*"
  - "packages/*"
```

**Root package.json:**

```json
{
  "name": "monorepo",
  "private": true,
  "scripts": {
    "build": "turbo build",
    "dev": "turbo dev",
    "lint": "turbo lint",
    "test": "turbo test",
    "format": "prettier --write \"**/*.{ts,tsx,md,json}\"",
    "changeset": "changeset",
    "version-packages": "changeset version",
    "release": "turbo build --filter='./packages/*' && changeset publish"
  },
  "devDependencies": {
    "@changesets/cli": "^2.27.0",
    "prettier": "^3.2.0",
    "turbo": "^2.3.0"
  },
  "packageManager": "pnpm@9.15.0"
}
```

### Shared ESLint Configuration

Create a shared ESLint config package that all apps and packages extend.

```json
// packages/config-eslint/package.json
{
  "name": "@repo/eslint-config",
  "version": "0.1.0",
  "private": true,
  "exports": {
    "./base": "./base.js",
    "./next": "./next.js",
    "./react": "./react.js",
    "./node": "./node.js"
  },
  "dependencies": {
    "@typescript-eslint/eslint-plugin": "^8.0.0",
    "@typescript-eslint/parser": "^8.0.0",
    "eslint-config-prettier": "^9.1.0",
    "eslint-plugin-import": "^2.29.0"
  }
}
```

```javascript
// packages/config-eslint/base.js
import tsPlugin from "@typescript-eslint/eslint-plugin";
import tsParser from "@typescript-eslint/parser";
import importPlugin from "eslint-plugin-import";

export default [
  {
    files: ["**/*.ts", "**/*.tsx"],
    plugins: {
      "@typescript-eslint": tsPlugin,
      import: importPlugin,
    },
    languageOptions: {
      parser: tsParser,
      parserOptions: {
        projectService: true,
      },
    },
    rules: {
      "@typescript-eslint/no-unused-vars": [
        "error",
        { argsIgnorePattern: "^_", varsIgnorePattern: "^_" },
      ],
      "@typescript-eslint/consistent-type-imports": "error",
      "import/order": [
        "error",
        {
          groups: [
            "builtin",
            "external",
            "internal",
            "parent",
            "sibling",
            "index",
          ],
          "newlines-between": "always",
          alphabetize: { order: "asc" },
        },
      ],
      "import/no-duplicates": "error",
    },
  },
];
```

**Consuming in an app:**

```javascript
// apps/web/eslint.config.js
import baseConfig from "@repo/eslint-config/base";
import nextConfig from "@repo/eslint-config/next";

export default [...baseConfig, ...nextConfig];
```

### Shared TypeScript Configuration

```json
// packages/config-typescript/package.json
{
  "name": "@repo/typescript-config",
  "version": "0.1.0",
  "private": true,
  "exports": {
    "./base": "./base.json",
    "./next": "./next.json",
    "./react-library": "./react-library.json",
    "./node": "./node.json"
  }
}
```

```json
// packages/config-typescript/base.json
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "compilerOptions": {
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "moduleResolution": "bundler",
    "module": "ESNext",
    "target": "ES2022",
    "lib": ["ES2022"],
    "resolveJsonModule": true,
    "isolatedModules": true,
    "incremental": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true
  },
  "exclude": ["node_modules", "dist"]
}
```

```json
// packages/config-typescript/next.json
{
  "$schema": "https://json.schemastore.org/tsconfig",
  "extends": "./base.json",
  "compilerOptions": {
    "lib": ["ES2022", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "jsx": "preserve",
    "plugins": [{ "name": "next" }],
    "paths": {
      "@/*": ["./src/*"]
    }
  }
}
```

**Consuming:**

```json
// apps/web/tsconfig.json
{
  "extends": "@repo/typescript-config/next",
  "include": ["next-env.d.ts", "**/*.ts", "**/*.tsx", ".next/types/**/*.ts"],
  "exclude": ["node_modules"]
}
```

### Internal Packages

Internal packages used within the monorepo but not published to npm.

```json
// packages/ui/package.json
{
  "name": "@repo/ui",
  "version": "0.1.0",
  "private": true,
  "exports": {
    ".": "./src/index.ts",
    "./button": "./src/button.tsx",
    "./card": "./src/card.tsx"
  },
  "devDependencies": {
    "@repo/typescript-config": "workspace:*",
    "react": "^19.0.0",
    "typescript": "^5.7.0"
  },
  "peerDependencies": {
    "react": "^19.0.0"
  }
}
```

**Key pattern: source-level imports (no build step for internal packages):**

```json
// turbo.json -- internal packages use "transit" (no build task)
{
  "$schema": "https://turbo.build/schema.json",
  "tasks": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**", "dist/**"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    },
    "lint": {
      "dependsOn": ["^lint"]
    },
    "test": {
      "dependsOn": ["^build"]
    }
  }
}
```

For internal packages consumed via source, Next.js transpiles them automatically:

```javascript
// apps/web/next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
  transpilePackages: ["@repo/ui", "@repo/utils"],
};

export default nextConfig;
```

### Changesets for Versioning and Publishing

```json
// .changeset/config.json
{
  "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
  "changelog": "@changesets/cli/changelog",
  "commit": false,
  "fixed": [],
  "linked": [["@repo/ui", "@repo/utils"]],
  "access": "public",
  "baseBranch": "main",
  "updateInternalDependencies": "patch",
  "ignore": ["@repo/eslint-config", "@repo/typescript-config"]
}
```

**Changeset workflow:**

```bash
# 1. Developer adds a changeset describing their change
pnpm changeset
# Interactive prompt: select packages, bump type, description

# 2. This creates a markdown file in .changeset/
# .changeset/funny-cats-dance.md
# ---
# "@repo/ui": minor
# "@repo/utils": patch
# ---
# Added new Button variant and updated color utility

# 3. CI or release manager versions packages
pnpm changeset version
# Updates package.json versions and CHANGELOG.md files

# 4. Publish to npm
pnpm changeset publish
```

**GitHub Actions for automated releases:**

```yaml
name: Release

on:
  push:
    branches: [main]

jobs:
  release:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - uses: pnpm/action-setup@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: pnpm

      - run: pnpm install --frozen-lockfile

      - name: Create Release PR or Publish
        uses: changesets/action@v1
        with:
          publish: pnpm release
          version: pnpm version-packages
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
```

### Shared Tailwind Configuration

```javascript
// packages/config-tailwind/tailwind.config.ts
import type { Config } from "tailwindcss";

const config: Omit<Config, "content"> = {
  theme: {
    extend: {
      colors: {
        brand: {
          50: "#eff6ff",
          500: "#3b82f6",
          600: "#2563eb",
          700: "#1d4ed8",
          900: "#1e3a8a",
        },
      },
      borderRadius: {
        DEFAULT: "0.5rem",
      },
      spacing: {
        18: "4.5rem",
        88: "22rem",
      },
    },
  },
  plugins: [],
};

export default config;
```

```typescript
// apps/web/tailwind.config.ts
import type { Config } from "tailwindcss";
import sharedConfig from "@repo/config-tailwind/tailwind.config";

const config: Config = {
  ...sharedConfig,
  content: [
    "./src/**/*.{ts,tsx}",
    "../../packages/ui/src/**/*.{ts,tsx}",  // Include shared UI
  ],
};

export default config;
```

## Best Practices

- **Use `workspace:*` protocol** for internal dependencies -- pnpm resolves them to the local package during development and replaces with actual versions on publish.
- **Prefer source-level imports** for internal packages -- skip the build step and let the consuming app's bundler handle transpilation.
- **Keep shared configs as separate packages** -- `@repo/eslint-config`, `@repo/typescript-config`, `@repo/config-tailwind`.
- **Use `linked` in Changesets** to version related packages together.
- **Mark internal-only packages as `private: true`** to prevent accidental publishing.
- **Include `transpilePackages`** in Next.js config for any workspace package imported from source.
- **Use Turborepo's `dependsOn: ["^build"]`** to ensure dependencies build before dependents.

## Common Pitfalls

| Pitfall | Problem | Fix |
|---------|---------|-----|
| Missing `workspace:*` protocol | pnpm fetches from npm registry instead of local | Use `"@repo/ui": "workspace:*"` in dependencies |
| Forgetting `transpilePackages` | Next.js fails to parse TypeScript from workspace packages | Add internal packages to `transpilePackages` array |
| Circular dependencies between packages | Build fails or infinite loops | Restructure -- extract shared types into a separate `@repo/types` package |
| Running `pnpm install` in a package subdirectory | Creates a separate lockfile | Always run `pnpm install` from the monorepo root |
| Publishing without Changesets | Version bumps are manual and error-prone | Use Changesets for automated, consistent versioning |
| Content paths missing shared UI | Tailwind misses classes from workspace packages | Add `../../packages/ui/src/**/*.{ts,tsx}` to content array |

## Git Strategies for Large Monorepos

### Sparse Checkout

Work with only a subset of the repository tree:

```bash
# Clone with sparse checkout (cone mode -- recommended)
git clone --sparse --filter=blob:none https://github.com/org/monorepo.git
cd monorepo
git sparse-checkout add packages/web packages/shared libs/utils
```

**CI (GitHub Actions):**

```yaml
- uses: actions/checkout@v4
  with:
    sparse-checkout: |
      packages/web
      packages/shared
      package.json
      pnpm-lock.yaml
    sparse-checkout-cone-mode: true
    fetch-depth: 1
```

### Shallow & Treeless Clones

```bash
# Shallow clone (fast CI, no history)
git clone --depth=1 --single-branch https://github.com/org/monorepo.git

# Treeless clone (full history, blobs on demand -- best balance)
git clone --filter=blob:none https://github.com/org/monorepo.git
```

| Strategy | Clone Time | Full History | Blame/Bisect |
|----------|-----------|--------------|--------------|
| Full clone | Slow | Yes | Yes |
| `--depth=1` | Fast | No | No |
| `--filter=blob:none` | Medium | Yes | Yes (on demand) |
| `--filter=blob:none --sparse` | Fast | Yes (sparse) | Yes |

### Git Worktrees

Work on multiple branches simultaneously without stashing:

```bash
git worktree add ../monorepo-feature-x feature/new-auth
git worktree add -b hotfix/urgent ../monorepo-hotfix main
git worktree list
git worktree remove ../monorepo-feature-x
```

### Git LFS

Track large binary files without bloating the repo:

```bash
git lfs install
git lfs track "*.psd" "*.mp4" "assets/models/**"
```

### Performance Tuning

```bash
git config core.fsmonitor true
git config core.untrackedCache true
git commit-graph write --reachable
git maintenance start
git config protocol.version 2
git config fetch.parallel 4
```

### Git Pitfalls

| Pitfall | Fix |
|---------|-----|
| `--depth=1` then `git blame` | Use `--filter=blob:none` instead |
| Forgetting lockfile in sparse checkout | Always include root config files |
| LFS pointers in CI | Add `git lfs install` step or `lfs: true` |
| Worktree on same branch | Use `git worktree add -b new-branch` |

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.