Back to Blog

Monorepo Tooling: Turborepo vs Nx, Workspace Setup, Shared Packages, and CI Optimization

Set up a production monorepo in 2026 — Turborepo vs Nx comparison, pnpm workspaces configuration, shared TypeScript packages, internal design system, CI pipelin

Viprasol Tech Team
June 19, 2026
12 min read

Monorepo Tooling: Turborepo vs Nx, Workspace Setup, Shared Packages, and CI Optimization

A monorepo keeps all related code in one repository. Instead of a separate repo for your web app, API, shared utilities, and design system, you have one repo with multiple packages. Dependencies between packages are local — no publishing to npm to use your own code.

The main challenge is build performance: as the repo grows, CI builds become slow if you rebuild everything on every change. The tools covered here (Turborepo, Nx) solve this with caching and dependency-aware task orchestration.


Turborepo vs Nx

TurborepoNx
Learning curveLow — minimal configMedium — more concepts (executors, generators)
Task cachingFile-based, remote cacheFile-based, remote cache, cloud cache
Code generationNone built-inGenerators for apps/libs/components
Framework supportAnyStrong Next.js, React, Angular, NestJS integration
Affected analysisTask-graph basedDeep dependency analysis with project graph
MigrationEasy to add to existing repoRequires more structure
Best forSimpler repos, existing pnpm workspacesLarge repos, multiple frameworks, strict structure

Recommendation: Start with Turborepo. If you grow into needing code generators, affected tests at scale, or framework-specific plugins, migrate to Nx.


Monorepo Structure

your-app/
├── apps/
│   ├── web/             # Next.js frontend
│   ├── api/             # Fastify backend
│   └── docs/            # Docusaurus documentation site
├── packages/
│   ├── ui/              # Shared React component library
│   ├── config/          # Shared ESLint, TypeScript, Prettier configs
│   ├── database/        # Prisma schema + generated client
│   └── utils/           # Shared utility functions
├── pnpm-workspace.yaml
├── turbo.json
├── package.json
└── tsconfig.json        # Root TypeScript config

🌐 Looking for a Dev Team That Actually Delivers?

Most agencies sell you a project manager and assign juniors. Viprasol is different — senior engineers only, direct Slack access, and a 5.0★ Upwork record across 100+ projects.

  • React, Next.js, Node.js, TypeScript — production-grade stack
  • Fixed-price contracts — no surprise invoices
  • Full source code ownership from day one
  • 90-day post-launch support included

pnpm Workspace Setup

# pnpm-workspace.yaml
packages:
  - 'apps/*'
  - 'packages/*'
// package.json (root)
{
  "name": "your-app",
  "private": true,
  "engines": { "node": ">=22", "pnpm": ">=9" },
  "scripts": {
    "build": "turbo build",
    "dev": "turbo dev",
    "test": "turbo test",
    "lint": "turbo lint",
    "type-check": "turbo type-check",
    "clean": "turbo clean && rm -rf node_modules"
  },
  "devDependencies": {
    "turbo": "^2.3.0",
    "typescript": "^5.4.0"
  }
}
// packages/ui/package.json — shared component library
{
  "name": "@acme/ui",
  "version": "0.0.0",
  "private": true,
  "main": "./dist/index.js",
  "module": "./dist/index.mjs",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.js",
      "types": "./dist/index.d.ts"
    }
  },
  "scripts": {
    "build": "tsup src/index.ts --format cjs,esm --dts",
    "dev": "tsup src/index.ts --format cjs,esm --dts --watch",
    "lint": "eslint src/",
    "type-check": "tsc --noEmit"
  },
  "peerDependencies": {
    "react": "^18 || ^19",
    "react-dom": "^18 || ^19"
  },
  "devDependencies": {
    "@acme/config": "workspace:*",
    "tsup": "^8.0.0"
  }
}
// apps/web/package.json — Next.js app
{
  "name": "@acme/web",
  "version": "0.0.0",
  "private": true,
  "dependencies": {
    "@acme/ui": "workspace:*",      // Local package — no npm publish
    "@acme/database": "workspace:*",
    "@acme/utils": "workspace:*",
    "next": "^15.0.0"
  }
}

Turborepo Configuration

// turbo.json
{
  "$schema": "https://turbo.build/schema.json",
  "globalDependencies": [".env"],
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],   // ^ = run deps' build first
      "outputs": [
        "dist/**",
        ".next/**",
        "!.next/cache/**"        // Don't cache Next.js build cache
      ],
      "cache": true
    },
    "dev": {
      "dependsOn": ["^build"],   // Build deps before starting dev servers
      "persistent": true,        // Long-running task (dev server)
      "cache": false
    },
    "test": {
      "dependsOn": ["^build"],
      "outputs": ["coverage/**"],
      "cache": true
    },
    "lint": {
      "outputs": [],
      "cache": true
    },
    "type-check": {
      "dependsOn": ["^build"],
      "outputs": [],
      "cache": true
    },
    "clean": {
      "cache": false
    }
  },
  "remoteCache": {
    "signature": true
  }
}

The ^build convention: runs build on all dependencies before running build on the current package. If web depends on ui, Turborepo builds ui first automatically.


🚀 Senior Engineers. No Junior Handoffs. Ever.

You get the senior developer, not a project manager who relays your requirements to someone you never meet. Every Viprasol project has a senior lead from kickoff to launch.

  • MVPs in 4–8 weeks, full platforms in 3–5 months
  • Lighthouse 90+ performance scores standard
  • Works across US, UK, AU timezones
  • Free 30-min architecture review, no commitment

Remote Caching

Remote cache means CI downloads cached outputs from a previous run instead of rebuilding. If packages/ui hasn't changed since the last CI run, its build output is downloaded from cache — 0ms build time for that package.

# Turborepo Remote Cache via Vercel (free)
npx turbo login
npx turbo link  # Links to your Vercel account's cache

# Self-hosted remote cache with ducktape
# (Alternative to Vercel's cache — for private/on-prem)
# See: https://github.com/ducktors/turborepo-remote-cache
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]

jobs:
  build-test:
    runs-on: ubuntu-latest
    env:
      TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}   # Vercel remote cache token
      TURBO_TEAM: ${{ secrets.TURBO_TEAM }}     # Vercel team slug

    steps:
      - uses: actions/checkout@v4

      - uses: pnpm/action-setup@v4
        with: { version: 9 }

      - uses: actions/setup-node@v4
        with:
          node-version: '22'
          cache: 'pnpm'

      - run: pnpm install --frozen-lockfile

      - name: Build (cached by Turborepo)
        run: pnpm turbo build

      - name: Test (cached by Turborepo)
        run: pnpm turbo test

      - name: Lint + Type check (cached)
        run: pnpm turbo lint type-check

CI time impact: Without remote cache, a full CI run might take 8 minutes. With remote cache on a PR that only touches apps/web, Turborepo skips the packages/ui and packages/database builds — total time drops to 2–3 minutes.


Shared Packages

Shared TypeScript config:

// packages/config/tsconfig.base.json
{
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["ES2022"],
    "module": "NodeNext",
    "moduleResolution": "NodeNext",
    "strict": true,
    "exactOptionalPropertyTypes": true,
    "noUncheckedIndexedAccess": true,
    "noImplicitOverride": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "declaration": true,
    "declarationMap": true,
    "sourceMap": true
  }
}

Shared database package with Prisma:

// packages/database/src/index.ts
import { PrismaClient } from '@prisma/client';

// Singleton pattern — avoid multiple PrismaClient instances in dev (Next.js hot reload)
const globalForPrisma = globalThis as unknown as { prisma?: PrismaClient };

export const prisma = globalForPrisma.prisma ?? new PrismaClient({
  log: process.env.NODE_ENV === 'development' ? ['query', 'error'] : ['error'],
});

if (process.env.NODE_ENV !== 'production') {
  globalForPrisma.prisma = prisma;
}

export * from '@prisma/client';  // Re-export all Prisma types
// packages/database/package.json
{
  "name": "@acme/database",
  "scripts": {
    "db:generate": "prisma generate",
    "db:migrate": "prisma migrate deploy",
    "db:studio": "prisma studio"
  },
  "devDependencies": { "prisma": "^5.0.0" },
  "dependencies": { "@prisma/client": "^5.0.0" }
}

Running Commands Across the Monorepo

# Run a command in a specific package
pnpm --filter @acme/web dev
pnpm --filter @acme/api build

# Run in all packages matching a pattern
pnpm --filter "./packages/**" build

# Run via Turborepo (with caching and dependency ordering)
turbo build --filter=@acme/web        # Build web and its deps
turbo test --filter=@acme/ui...       # Test ui and everything that depends on ui
turbo lint --filter=[HEAD^1]          # Lint only packages changed since last commit

# Generate a new component in the ui package
cd packages/ui && pnpm plop component  # If using plop for codegen

Working With Viprasol

We set up monorepo infrastructure for engineering teams — Turborepo or Nx configuration, pnpm workspace design, shared packages, remote caching pipelines, and CI optimization that keeps build times under 5 minutes as repos grow.

Talk to our team about developer tooling and monorepo architecture.


See Also

Share this article:

About the Author

V

Viprasol Tech Team

Custom Software Development Specialists

The Viprasol Tech team specialises in algorithmic trading software, AI agent systems, and SaaS development. With 100+ projects delivered across MT4/MT5 EAs, fintech platforms, and production AI systems, the team brings deep technical experience to every engagement. Based in India, serving clients globally.

MT4/MT5 EA DevelopmentAI Agent SystemsSaaS DevelopmentAlgorithmic Trading

Need a Modern Web Application?

From landing pages to complex SaaS platforms — we build it all with Next.js and React.

Free consultation • No commitment • Response within 24 hours

Viprasol · Web Development

Need a custom web application built?

We build React and Next.js web applications with Lighthouse ≥90 scores, mobile-first design, and full source code ownership. Senior engineers only — from architecture through deployment.