Skip to main content
Back to Blog
Architecture

Structuring Full-Stack Monorepos with pnpm and Turborepo

NT

NeoCodeHub Team

November 1, 2025

When your project has a Next.js frontend, NestJS API, shared types, and validation schemas, a monorepo keeps everything in sync. We've refined this structure across multiple projects.

Why pnpm Over npm or Yarn

pnpm's hard-linked node_modules save 60%+ disk space. Strict dependency resolution prevents phantom dependencies — if a package isn't in your package.json, you can't import it. The workspace protocol makes local package references explicit and reliable.

Shared Packages

The key insight of monorepos is sharing code between frontend and backend. Our shared packages include TypeScript type definitions (used by both Next.js and NestJS), Zod validation schemas (same rules for frontend forms and backend API validation), and configuration (shared ESLint and TypeScript configs).

Turborepo Build Orchestration

Turborepo understands the dependency graph between packages. When you change a shared type, it rebuilds only the packages that depend on it. Build caching means unchanged packages skip compilation entirely. CI runs only affected tests.

Handling Non-Node Packages

In Errandoo, the Flutter mobile app lives in the monorepo but isn't managed by pnpm. We add a minimal package.json shim so Turborepo can include it in the dependency graph for build ordering, while Flutter's own toolchain handles the actual build.

When Monorepos Hurt

Monorepos add complexity. If your frontend and backend teams deploy independently and rarely share code, separate repos are simpler. The monorepo pays off when teams share types, validation logic, or configuration — which is most full-stack TypeScript projects.

Related Posts