CI/CD in Monorepo Structure: Turborepo and GitHub Actions Integration

CI/CD in Monorepo Structure: Turborepo and GitHub Actions Integration

Managing multiple applications and packages in a single repository can turn into chaos without the right tools. Turborepo dramatically speeds up CI/CD processes in monorepo projects with its smart caching and task pipeline mechanism. This guide walks you through Turborepo setup, GitHub Actions integ

C

Can Kaya

Security Specialist

March 21, 202612 min read0

Managing multiple applications and packages in a single repository can turn into chaos without the right tools. Turborepo dramatically speeds up CI/CD processes in monorepo projects with its smart caching and task pipeline mechanism. This guide walks you through Turborepo setup, GitHub Actions integration, remote caching, and affected filtering step by step.

Monorepo vs Polyrepo Comparison

The choice between monorepo and polyrepo depends on team size, project structure, and deployment strategy. The table below summarizes the key differences.

Feature Monorepo Polyrepo
Code sharing Easy (internal packages) Difficult (npm publish required)
CI/CD complexity Medium (with affected filter) Low (independent pipelines)
Dependency management Centralized (single lock file) Distributed (separate per repo)
Atomic changes Possible with single PR Multiple PRs required
Repo size Large (all code in one place) Small (isolated repos)

💡 Tip: If you have 3+ applications and shared packages, a monorepo structure simplifies code sharing and version compatibility. Tools like Turborepo, Nx, or Lerna make this process manageable.

Turborepo Setup and Project Structure

Turborepo is a high-performance monorepo build system developed by Vercel. Creating a new project or adding it to an existing one is straightforward.

terminal
# Create a new monorepo project
npx create-turbo@latest my-monorepo

# Add Turborepo to an existing project
npm install turbo --save-dev

# Project structure
my-monorepo/
├── apps/
│   ├── web/          # Next.js frontend
│   ├── api/          # Express backend
│   └── admin/        # Admin panel
├── packages/
│   ├── ui/           # Shared UI components
│   ├── config/       # ESLint, TS config
│   └── utils/        # Common utility functions
├── turbo.json
├── package.json
└── pnpm-workspace.yaml

Define your workspace directories in pnpm-workspace.yaml:

pnpm-workspace.yaml
packages:
  - "apps/*"
  - "packages/*"

Task Pipeline Configuration (turbo.json)

Turborepo's power comes from the task pipeline definitions in turbo.json. Each task's dependencies, outputs, and cache behavior are defined here.

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

⚠️ Warning: The ^build notation means "run the build task of dependencies first." This ensures packages/ui is built before apps/web. If the ordering is wrong, the build will fail.

GitHub Actions with Affected Filter

Building all applications on every push in a monorepo is wasteful. With Turborepo's --filter flag, you can build only the changed packages and their dependents.

.github/workflows/ci.yml
name: CI
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 2

      - uses: pnpm/action-setup@v3
        with:
          version: 9

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

      - run: pnpm install --frozen-lockfile

      # Build only changed packages
      - run: pnpm turbo build --filter=...[HEAD^1]

      # Run tests for changed packages
      - run: pnpm turbo test --filter=...[HEAD^1]

      # Lint check
      - run: pnpm turbo lint --filter=...[HEAD^1]

The --filter=...[HEAD^1] expression selects packages changed since the last commit and all packages that depend on them. In a monorepo with 10 applications, if only 2 changed, only those 2 get built.

Speeding Up Builds with Remote Caching

One of Turborepo's most powerful features is remote caching. When a developer or CI runner writes build output to the cache, another runner with the same input can skip the build entirely by using that cache.

.github/workflows/ci.yml (remote cache)
jobs:
  build:
    runs-on: ubuntu-latest
    env:
      TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
      TURBO_TEAM: ${{ vars.TURBO_TEAM }}
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v3
      - uses: actions/setup-node@v4
        with:
          node-version: 20
          cache: "pnpm"
      - run: pnpm install --frozen-lockfile
      # Remote cache is automatically active
      - run: pnpm turbo build test lint

💡 Tip: Remote caching reduces average CI times by 40-65%. Vercel Remote Cache is free to use, or you can set up a self-hosted cache server. Connect your account with turbo login and turbo link commands.

For CI/CD pipeline fundamentals, check our GitHub Actions CI/CD guide. For GitOps approach, see our ArgoCD guide. For deployment strategies, explore our Blue-Green and Canary Deployment guide. Turborepo Official Documentation and GitHub Actions Documentation are valuable additional resources.

Frequently Asked Questions

What is the difference between Turborepo and Nx?

Turborepo is lighter and easier to configure, focusing specifically on JavaScript/TypeScript projects. Nx offers a more comprehensive ecosystem with code generation and a plugin system supporting multiple languages. Turborepo is preferred for small-to-medium projects, while Nx suits large enterprise projects.

Can each application be deployed independently in a monorepo?

Yes, with Turborepo's filter mechanism you can build and deploy each application independently. Use commands like --filter=web to target a specific application.

Is remote caching secure?

Vercel Remote Cache stores artifacts encrypted and only authorized team members can access them. For self-hosted solutions, HTTPS and token-based authentication should be used.

Does Git performance degrade in a monorepo?

Git operations can slow down in large monorepos. Use Git sparse-checkout and shallow clone to pull only necessary directories in CI. Setting fetch-depth: 2 in GitHub Actions mitigates this issue.

Conclusion

The Turborepo and GitHub Actions combination makes CI/CD processes in monorepo projects fast, efficient, and manageable. Automate dependency ordering with task pipelines, skip unnecessary builds with affected filters, and dramatically reduce CI times with remote caching.

Fast Infrastructure for Monorepo CI/CD

Speed up your build and deploy processes with Hosted Cloud servers.

Explore Cloud Server Plans →
C

Can Kaya

Security Specialist

CISSP-certified security expert creating content on cybersecurity, DDoS protection, and server hardening.

Comments coming soon