Monorepos have transformed how teams manage large codebases, enabling shared code, atomic commits, and unified tooling. But deploying from a monorepo presents unique challenges: selective deployments, dependency management, and build optimization. In this guide, you'll learn strategies for deploying monorepos with [DeployHQ](https://www.deployhq.com) using Nx, Turborepo, and other tools.

## Why Monorepos?

Monorepos consolidate multiple projects into a single repository, offering significant benefits:

- **Atomic commits** across related packages
- **Shared code** without npm publishing
- **Unified CI/CD** pipelines
- **Consistent tooling** and standards
- **Simplified dependency management**

```
flowchart TD
    subgraph "Polyrepo"
        R1[repo-frontend]
        R2[repo-backend]
        R3[repo-shared]
        R1 -.-> |npm install| R3
        R2 -.-> |npm install| R3
    end

    subgraph "Monorepo"
        M[monorepo]
        M --> F[packages/frontend]
        M --> B[packages/backend]
        M --> S[packages/shared]
        F --> |direct import| S
        B --> |direct import| S
    end
```

## Monorepo Structure

A typical monorepo structure looks like this:

```
my-monorepo/
├── apps/
│ ├── web/ # Frontend application
│ │ ├── src/
│ │ └── package.json
│ ├── api/ # Backend API
│ │ ├── src/
│ │ └── package.json
│ └── admin/ # Admin dashboard
│ ├── src/
│ └── package.json
├── packages/
│ ├── ui/ # Shared UI components
│ │ ├── src/
│ │ └── package.json
│ ├── utils/ # Shared utilities
│ │ └── package.json
│ └── config/ # Shared configuration
│ └── package.json
├── package.json # Root package.json
├── nx.json # Nx configuration
├── turbo.json # Turborepo configuration
└── pnpm-workspace.yaml # Workspace definition
```

## Nx: Enterprise-Scale Monorepos

Nx provides powerful features for large monorepos, including computation caching, affected commands, and task orchestration.

### Nx Project Setup

```
// nx.json
{
  "npmScope": "mycompany",
  "tasksRunnerOptions": {
    "default": {
      "runner": "nx/tasks-runners/default",
      "options": {
        "cacheableOperations": ["build", "test", "lint"]
      }
    }
  },
  "targetDefaults": {
    "build": {
      "dependsOn": ["^build"],
      "inputs": ["production", "^production"]
    },
    "test": {
      "inputs": ["default", "^production"]
    }
  },
  "namedInputs": {
    "default": ["{projectRoot}/**/*", "sharedGlobals"],
    "production": ["default", "!{projectRoot}/**/*.spec.ts"],
    "sharedGlobals": []
  }
}
```

### App Configuration

```
// apps/web/project.json
{
  "name": "web",
  "sourceRoot": "apps/web/src",
  "projectType": "application",
  "targets": {
    "build": {
      "executor": "@nx/vite:build",
      "outputs": ["{options.outputPath}"],
      "options": {
        "outputPath": "dist/apps/web"
      }
    },
    "deploy": {
      "executor": "nx:run-commands",
      "options": {
        "command": "deployhq-deploy web"
      },
      "dependsOn": ["build"]
    }
  }
}
```

### DeployHQ Build Commands with Nx

```
# Install dependencies
pnpm install --frozen-lockfile

# Determine affected projects
AFFECTED=$(npx nx affected:apps --plain --base=origin/main~1 --head=HEAD)

# Build only affected apps
if [-n "$AFFECTED"]; then
    echo "Building affected apps: $AFFECTED"
    npx nx affected:build --base=origin/main~1 --head=HEAD
else
    echo "No apps affected, skipping build"
fi
```

### Selective Deployment Script

```
#!/bin/bash
# .deployhq/deploy.sh

set -e

# Get list of affected apps
AFFECTED_APPS=$(npx nx affected:apps --plain --base=origin/main~1 --head=HEAD)

# Deploy each affected app
for app in $AFFECTED_APPS; do
    echo "=== Deploying $app ==="

    case $app in
        web)
            rsync -avz dist/apps/web/ user@web-server:/var/www/web/
            ;;
        api)
            rsync -avz dist/apps/api/ user@api-server:/var/www/api/
            ssh user@api-server "pm2 restart api"
            ;;
        admin)
            rsync -avz dist/apps/admin/ user@admin-server:/var/www/admin/
            ;;
        *)
            echo "Unknown app: $app"
            ;;
    esac
done

echo "=== Deployment complete ==="
```

For more on [build pipelines](https://www.deployhq.com/blog/build-pipelines-in-deployhq-streamline-your-deployment-workflow), see our dedicated guide.

## Turborepo: Fast Monorepo Builds

Turborepo focuses on build speed through intelligent caching and parallel execution.

### Turborepo Configuration

```
// turbo.json
{
  "$schema": "https://turbo.build/schema.json",
  "globalDependencies": ["**/.env.*local"],
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/ **", ".next/**", "!.next/cache/**"]
    },
    "test": {
      "dependsOn": ["build"],
      "inputs": ["src/ **/*.tsx", "src/** /*.ts", "test/**/*.ts"]
    },
    "lint": {
      "outputs": []
    },
    "deploy": {
      "dependsOn": ["build", "test", "lint"],
      "cache": false
    }
  }
}
```

### DeployHQ Build Commands with Turborepo

```
# Install dependencies
pnpm install --frozen-lockfile

# Run build with Turborepo caching
npx turbo run build --filter=...@mycompany/web

# Or build all changed since last deploy
npx turbo run build --filter=[origin/main~1]
```

### Remote Caching for CI

Enable remote caching to speed up builds across deployments:

```
# Enable Turborepo remote caching
npx turbo login
npx turbo link

# Build with remote cache
TURBO_TEAM="myteam" TURBO_TOKEN="$TURBO_TOKEN" npx turbo run build
```

## Package Manager Considerations

Monorepos work best with modern package managers:

### pnpm Workspaces

```
# pnpm-workspace.yaml
packages:
  - 'apps/*'
  - 'packages/*'
```

```
# Install with pnpm
pnpm install --frozen-lockfile

# Run command in specific package
pnpm --filter @mycompany/web build

# Run command in all packages
pnpm -r build
```

### npm Workspaces

```
// package.json
{
  "workspaces": [
    "apps/*",
    "packages/*"
  ]
}
```

For a comparison of package managers, see our guide on [choosing the right package manager](https://www.deployhq.com/blog/choosing-the-right-package-manager-npm-vs-yarn-vs-pnpm-vs-bun).

## Deployment Strategies

### Strategy 1: Deploy All Apps

Simple but potentially wasteful:

```
# Build everything
npx turbo run build

# Deploy all apps
for app in apps/*; do
    deploy_app $app
done
```

### Strategy 2: Deploy Affected Only

Efficient for large monorepos:

```
flowchart LR
    A[Code Change] --> B{What Changed?}
    B -->|packages/utils| C[Rebuild All Dependents]
    B -->|apps/web| D[Rebuild web Only]
    B -->|apps/api| E[Rebuild api Only]
    C --> F[Deploy Affected]
    D --> F
    E --> F
```

```
# Get affected apps
AFFECTED=$(npx nx affected:apps --plain)

# Build and deploy only affected
for app in $AFFECTED; do
    npx nx build $app
    deploy_app $app
done
```

### Strategy 3: Per-App Projects in DeployHQ

Create separate [DeployHQ](https://www.deployhq.com) projects for each app, each with filtered build commands:

```
# Project: Web App
npx turbo run build --filter=@mycompany/web
# Deploy dist/apps/web

# Project: API
npx turbo run build --filter=@mycompany/api
# Deploy dist/apps/api
```

This is where [DeployHQ](https://www.deployhq.com) shines: give each app its own project with [per-project build pipelines](https://www.deployhq.com/features/build-pipelines) and filtered build commands, so a change to `apps/web` never redeploys `apps/api`. [Deploy your first monorepo app free](https://www.deployhq.com/signup).

## Environment Configuration

Manage environment variables across apps:

```
// packages/config/src/env.ts
export function getEnvConfig(appName: string) {
  const common = {
    NODE_ENV: process.env.NODE_ENV || 'development',
    LOG_LEVEL: process.env.LOG_LEVEL || 'info',
  };

  const appSpecific = {
    web: {
      API_URL: process.env.WEB_API_URL,
      PUBLIC_URL: process.env.WEB_PUBLIC_URL,
    },
    api: {
      DATABASE_URL: process.env.API_DATABASE_URL,
      REDIS_URL: process.env.API_REDIS_URL,
    },
  };

  return {
    ...common,
    ...appSpecific[appName],
  };
}
```

For managing environments, see [managing multiple environments with DeployHQ](https://www.deployhq.com/blog/managing-multiple-environments-with-deployhq-dev-staging-and-production).

## Dependency Graph Visualization

Understanding your dependency graph helps optimize deployments:

```
# Generate dependency graph with Nx
npx nx graph

# Export as JSON
npx nx graph --file=graph.json
```

```
flowchart TD
    subgraph "Apps"
        web[web]
        api[api]
        admin[admin]
    end

    subgraph "Packages"
        ui[ui]
        utils[utils]
        config[config]
    end

    web --> ui
    web --> utils
    web --> config
    admin --> ui
    admin --> utils
    api --> utils
    api --> config
    ui --> utils
```

## Testing in Monorepos

Run tests efficiently:

```
# Test only affected packages
npx nx affected:test --base=origin/main

# Test specific app and its dependencies
npx turbo run test --filter=@mycompany/web...

# Test all packages in parallel
npx turbo run test --parallel
```

## Best Practices Summary

1. **Use affected commands** to build/deploy only changed code
2. **Enable caching** (local and remote) for faster builds
3. **Structure dependencies** clearly between packages
4. **Use workspace protocols** for internal dependencies
5. **Configure clear pipelines** for build, test, and deploy
6. **Separate concerns** between apps and shared packages
7. **Version together** or use independent versioning thoughtfully
8. **Monitor build times** and optimize bottlenecks

## Getting Started

Ready to deploy your monorepo? Here's your checklist:

1. Choose your monorepo tool (Nx or Turborepo)
2. Set up workspace configuration
3. Configure [DeployHQ](https://www.deployhq.com) build commands
4. Implement affected/filtered builds
5. Set up per-app deployments

New to automated deploys? Start with our guide to [building a CI/CD pipeline from scratch](https://www.deployhq.com/blog/building-a-ci-cd-pipeline-from-scratch-with-deployhq-a-step-by-step-guide), then layer in the monorepo filters above.

For Node.js-specific guidance, see our guide on [Node application servers](https://www.deployhq.com/blog/node-application-servers-in-2025-from-express-to-modern-solutions).

* * *

Questions about monorepo deployments? Reach out to [support@deployhq.com](mailto:support@deployhq.com) or follow [@deployhq](https://x.com/deployhq) for deployment tips.

