Emmanuel Okeke

[0%] 3/7

← cd /blogEngineering

Building a Monorepo with Turborepo and pnpm

$ cat --info "building-a-monorepo.mdx"

> published: 2026-05-20 | read_time: 2 min read | category: engineering


Why a Monorepo?

When my portfolio grew beyond a single Next.js app — adding a backend API for project data, a chatbot service, and shared utilities — managing separate repositories became painful. Every change that touched shared types required coordinating deploys across repos.

I chose Turborepo with pnpm workspaces for three reasons:

  1. Incremental builds — Turbo caches build outputs and only rebuilds what changed
  2. Shared configuration — ESLint, TypeScript, and Prettier configs live in one place
  3. Atomic changes — A single PR can update the API contract and the frontend consumer

The Structure

The monorepo splits into two main packages:

  • packages/frontend — Next.js 14 with Chakra UI, Three.js for 3D elements, and Framer Motion
  • packages/backend — Express API serving project data, connected to MongoDB

Shared TypeScript interfaces live in the root and are referenced by both packages.

Deployment Strategy

Each package deploys independently:

  • Frontend → Vercel (automatic deploys on push to main)
  • Backend → Railway (Dockerfile-based, auto-scales)

The key insight was configuring Vercel's root directory to packages/frontend and letting Turbo handle the build graph. One pnpm turbo build --filter=frontend command resolves all internal dependencies before bundling.

Lessons Learned

The biggest surprise was dependency hoisting. pnpm's strict node_modules structure caught several packages that relied on phantom dependencies — packages that worked in flat node_modules but broke under pnpm's isolated structure. Fixing these early saved debugging time later.

See related project →

← Previous

Shadow Mode: A Production Dry-Run for Rules

3 of 7

Next →

TinyOps Speaks MCP Now