# Monorepo Management Strategies with Turborepo and pnpm: A Production-Grade Implementation Guide

> Implement production-grade monorepo management with Turborepo and pnpm. Optimize your JavaScript projects for scalability and maintainability using advanced task orchestration and caching.

- Repository: [Alireza Rezvani/claude-skills](https://github.com/alirezarezvani/claude-skills)
- Tags: how-to-guide
- Published: 2026-03-09

---

**Use pnpm workspaces for package linking and Turborepo for task orchestration, caching, and affected-package detection to build scalable, maintainable JavaScript monorepos.**

Modern JavaScript/TypeScript monorepos require disciplined tooling to manage dependencies, tasks, and versioning at scale. The *Monorepo Navigator* skill in the `alirezarezvani/claude-skills` repository provides a complete reference implementation demonstrating effective **monorepo management strategies with Turborepo and pnpm**. This guide extracts the architectural patterns, configuration files, and CLI workflows directly from the source code to help you implement a low-maintenance, high-performance monorepo.

## Defining the Workspace Structure

Every pnpm-based monorepo starts with a root-level workspace definition. In the `alirezarezvani/claude-skills` implementation, the [`pnpm-workspace.yaml`](https://github.com/alirezarezvani/claude-skills/blob/main/pnpm-workspace.yaml) file declares three distinct directory globs that organize code by responsibility.

```yaml

# pnpm-workspace.yaml

packages:
  - "apps/*"
  - "packages/*"
  - "tools/*"

```

This structure separates deployable applications (`apps`), shared libraries (`packages`), and internal tooling (`tools`). According to the documentation in [`engineering/monorepo-navigator/SKILL.md`](https://github.com/alirezarezvani/claude-skills/blob/main/engineering/monorepo-navigator/SKILL.md), this convention ensures that pnpm treats every subdirectory within these paths as an individual package while maintaining a single root lockfile.

## Configuring the Turborepo Pipeline

Turborepo orchestrates tasks across the workspace using a directed acyclic graph (DAG) defined in [`turbo.json`](https://github.com/alirezarezvani/claude-skills/blob/main/turbo.json). The configuration in this repository demonstrates how to declare dependencies between tasks and enable aggressive caching.

```json
{
  "$schema": "https://turbo.build/schema.json",
  "globalEnv": ["NODE_ENV", "DATABASE_URL"],
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": [".next/**", "dist/**", "build/**"]
    },
    "test": {
      "dependsOn": ["^build"],
      "outputs": ["coverage/**"],
      "cache": true
    },
    "lint": {
      "outputs": [],
      "cache": true
    },
    "dev": {
      "cache": false,
      "persistent": true
    }
  }
}

```

The `dependsOn` array uses the `^` prefix to indicate that a task depends on the same task in its dependencies (e.g., `test` waits for upstream packages to finish `build`). As documented in [`engineering/monorepo-navigator/SKILL.md`](https://github.com/alirezarezvani/claude-skills/blob/main/engineering/monorepo-navigator/SKILL.md), the `globalEnv` array ensures that changes to environment variables invalidate the cache appropriately.

## Linking Packages with the Workspace Protocol

Cross-package dependencies resolve via the **workspace protocol**, guaranteeing that imports always point to the current source tree rather than published registry versions.

```json
// apps/web/package.json
{
  "name": "@myorg/web",
  "dependencies": {
    "@myorg/ui": "workspace:*",
    "@myorg/utils": "workspace:^"
  }
}

```

The `workspace:*` protocol pins the dependency to the exact version in the monorepo, while `workspace:^` allows caret-range semantics. This approach, detailed in the skill documentation, eliminates version drift during development and ensures that changes in `packages/ui` immediately reflect in `apps/web` without publishing.

## Executing Tasks and Affected Package Detection

Turborepo’s selective execution filters minimize CI time by running tasks only on packages that changed since the last commit. The repository demonstrates two primary filter patterns:

```bash

# Build only packages affected by the last commit

turbo run build --filter=...[HEAD^1]

# Build a specific package and all its dependencies

turbo run build --filter=@myorg/web...

```

The `...[HEAD^1]` syntax calculates the minimal subgraph requiring rebuild by comparing the current commit against its parent. For CI pipelines targeting pull requests, the repository uses `--filter=...[origin/main]` to detect changes relative to the main branch, as shown in [`docs/skills/engineering/monorepo-navigator.md`](https://github.com/alirezarezvani/claude-skills/blob/main/docs/skills/engineering/monorepo-navigator.md).

To preview execution without running commands, use the dry-run flag:

```bash
turbo run build --dry-run

```

## Remote Caching for CI Acceleration

The `alirezarezvani/claude-skills` repository emphasizes **remote caching** to share task outputs across CI runners and local machines. By storing compiled assets and test results in a remote cache keyed by input hashes, teams avoid redundant computation.

Enable Vercel Remote Cache with:

```bash
turbo login
turbo link

```

Alternatively, self-hosted cache servers provide the same functionality for private infrastructure. The configuration in [`.github/workflows/ci-quality-gate.yml`](https://github.com/alirezarezvani/claude-skills/blob/main/.github/workflows/ci-quality-gate.yml) demonstrates passing authentication tokens via environment variables:

```yaml
- name: Build affected
  run: turbo run build --filter=...[origin/main]
  env:
    TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
    TURBO_TEAM: ${{ vars.TURBO_TEAM }}

```

## Versioning and Publishing with Changesets

Manual version bumps become unmanageable in large monorepos. The reference implementation uses **Changesets** to automate changelog generation, version bumping, and publishing.

```bash

# Create a changeset after modifying packages

pnpm changeset

# Version bump and publish in CI

pnpm changeset version
pnpm changeset publish

```

As documented in [`docs/skills/engineering/monorepo-navigator.md`](https://github.com/alirezarezvani/claude-skills/blob/main/docs/skills/engineering/monorepo-navigator.md), this workflow replaces manual edits to [`package.json`](https://github.com/alirezarezvani/claude-skills/blob/main/package.json) files, ensures deterministic publishing order based on the dependency graph, and supports pre-release channels for beta testing.

## Documentation and Discovery Standards

The repository establishes documentation conventions that scale with the codebase. A root-level [`CLAUDE.md`](https://github.com/alirezarezvani/claude-skills/blob/main/CLAUDE.md) maps the overall monorepo structure, while individual packages contain scoped [`CLAUDE.md`](https://github.com/alirezarezvani/claude-skills/blob/main/CLAUDE.md) files enforcing specific testing rules and command patterns. This approach, referenced in [`engineering/monorepo-navigator/SKILL.md`](https://github.com/alirezarezvani/claude-skills/blob/main/engineering/monorepo-navigator/SKILL.md), enables AI assistants and new developers to navigate the codebase without deep institutional knowledge.

## Summary

- **pnpm workspaces** define the monorepo boundary via [`pnpm-workspace.yaml`](https://github.com/alirezarezvani/claude-skills/blob/main/pnpm-workspace.yaml), organizing code into `apps`, `packages`, and `tools` directories.
- **Turborepo pipelines** in [`turbo.json`](https://github.com/alirezarezvani/claude-skills/blob/main/turbo.json) declare task dependencies and caching rules, enabling parallel execution and output reuse.
- The **workspace protocol** (`workspace:*`) ensures cross-package dependencies resolve to local source, eliminating version conflicts during development.
- **Affected detection** via `--filter=...[HEAD^1]` or `--filter=...[origin/main]` minimizes CI execution time by targeting only changed packages.
- **Remote caching** (Vercel or self-hosted) shares task outputs across machines, dramatically reducing build and test durations.
- **Changesets** automate versioning and publishing workflows, replacing manual package bumps with structured change documentation.

## Frequently Asked Questions

### How does pnpm differ from npm or Yarn in a monorepo context?

pnpm uses a content-addressable store and hard links to share dependencies across packages, consuming significantly less disk space than npm or Yarn Classic. Its workspace implementation requires explicit [`pnpm-workspace.yaml`](https://github.com/alirezarezvani/claude-skills/blob/main/pnpm-workspace.yaml) configuration and supports the `workspace:` protocol natively, providing stricter control over internal dependency resolution than Yarn's `link:` protocol or npm workspaces.

### What is the purpose of the `dependsOn` configuration in turbo.json?

The `dependsOn` array defines the task dependency graph that Turborepo uses to schedule execution. The `^` prefix indicates a topological dependency—meaning a package's `build` task waits for its dependencies' `build` tasks to complete. This ensures that downstream packages never consume stale artifacts from upstream changes.

### How do you determine which packages need rebuilding in CI?

Use the `--filter` flag with a Git reference range. The syntax `--filter=...[origin/main]` tells Turborepo to select packages that changed between the current commit and the main branch, plus their dependents. This calculated subgraph represents the minimal set requiring validation, reducing CI costs and execution time.

### Can Turborepo work with other package managers like npm or Yarn?

Yes, Turborepo is package-manager agnostic and works with npm, Yarn, and pnpm. However, the `alirezarezvani/claude-skills` repository specifically recommends pnpm for its strict workspace isolation, efficient storage, and native support for the `workspace:` protocol, which simplifies internal dependency management compared to npm or Yarn implementations.