Article Information
Category: Development
Published: 13 March, 2026
Author: Chris de Gruijter
Reading Time: 10 min
Tags

Why I Use Turborepo for Multi-App Projects: Real Benefits from Managing 10+ Apps in Two Monorepos
Published: 13 March, 2026
When you're managing a single website, project structure doesn't matter much. Throw everything in one folder, deploy it, move on. But when you're running five websites, a dashboard, a documentation site, shared UI components, and deployment scripts — all for the same agency — things get messy fast.
I run two Turborepo monorepos: one for Webfluentia (the agency's own sites and tools) and one for a client group. Between them, that's 10+ apps sharing code, configs, and deployment pipelines. Here's why Turborepo works for this setup, what problems it actually solves, and where it falls short.
What My Monorepos Look Like
The Webfluentia turborepo contains five apps and three shared packages:
- apps/wf-main — Nuxt 3 agency website (webfluentia.agency)
- apps/dashboard — Next.js 16 unified client dashboard (dashboard.webfluentia.agency)
- apps/personal/cjv-main — Nuxt 3 portfolio site (cjvdegruijter.nl)
- apps/personal/cjv-dj — Static HTML DJ portfolio
- apps/personal/cjv-vcard — Static HTML vCard page
- packages/eslint-config — Shared ESLint configuration
- packages/typescript-config — Shared tsconfig presets
- packages/ui — Shared React UI components
The second turborepo follows the same pattern with five client-facing apps (blog, SOP portal, docs, dev environment, main site) plus shared packages for consent management, UI components, and TypeScript config.
The Benefits I Actually Experience
1. Shared Configuration, Written Once
Before monorepos, I had the same ESLint config copy-pasted across 8 projects. Updating a rule meant opening each project and making the same change. With Turborepo, the ESLint config lives in packages/eslint-config and every app extends it. Change it once, every app picks it up on the next lint run.
Same story for TypeScript configuration. Strict mode settings, path aliases, compiler options — all defined in packages/typescript-config and referenced by each app's tsconfig.json. No drift between projects.
2. Independent Deployments with Shared Code
Each app deploys independently to its own Cloudflare Pages project. The Nuxt sites generate static output, the Next.js dashboard deploys as a Cloudflare Worker, and the static HTML sites just upload files. Turborepo doesn't force a unified deployment — each app has its own build and deploy scripts in the deployment/ directory.
The key insight: monorepo ≠ monolith. Apps share code at build time but are completely independent at runtime. The dashboard doesn't know the portfolio site exists, and vice versa.
3. Faster Builds with Caching
Turborepo's build cache is the headline feature, and it delivers. When I run turbo run build, only the apps that changed (or whose dependencies changed) actually rebuild. The rest are served from cache. For a monorepo with 5 apps, this cuts build time from minutes to seconds when you're only working on one app.
# First build: all apps
$ turbo run build
# → 5 apps built, 47s total
# After changing only cjv-main:
$ turbo run build
# → 1 app built, 4 cached, 12s total4. Filtered Development
The --filter flag is something I use constantly. Instead of running all 5 dev servers, I start just the one I'm working on:
# Only start the dashboard dev server
pnpm --filter wf-dashboard-next dev
# Or use the convenience scripts in package.json
pnpm dev:dashboard
pnpm dev:cjv-main
pnpm dev:wf-mainThis keeps resource usage low and startup fast. No reason to run a Nuxt dev server when you're working on a Next.js app.
5. Atomic Changes Across Apps
When I update a shared TypeScript type or a UI component, I can see the impact across all apps in a single commit. No more "update type definition" PRs across 5 separate repos. The change and its consumers are all in one place, making code review straightforward.
The pnpm Workspace Setup
Turborepo works on top of your package manager's workspace feature. I use pnpm workspaces with a simple configuration:
packages:
- "apps/**"
- "packages/*"The apps/** glob with double wildcards is important — it allows nested app directories like apps/personal/cjv-main. With a single wildcard (apps/*), pnpm wouldn't discover apps in subdirectories.
Each app has its own package.json with its own dependencies. Shared packages are referenced by name (e.g., "@webfluentia/eslint-config": "workspace:*"), and pnpm links them automatically. No npm publishing, no version management — just local workspace references.
Mixing Next.js and Nuxt in One Repo
One question I get asked: can you mix framework ecosystems in a Turborepo? Yes, and it works fine. My Webfluentia monorepo has both Next.js (dashboard) and Nuxt (agency site, portfolio) apps. They don't share runtime code — React components can't be used in Vue apps — but they share:
- TypeScript configuration — compiler options, strict mode settings
- ESLint rules — the base config works for both, with framework-specific extends
- Deployment scripts — shell scripts for building and deploying to Cloudflare
- Documentation — all project docs live in the monorepo's
docs/directory - Environment patterns — consistent
.env.examplefiles and secret management
The packages/ui package contains React components used only by the Next.js dashboard. If I had Vue-based shared components, I'd create a separate packages/ui-vue package. The monorepo structure accommodates this naturally.
Where Turborepo Falls Short
It's not all upside. Here are the friction points I've encountered:
- IDE performance — With 10+ apps, some IDEs struggle with TypeScript language server performance. Windsurf handles it well, but I've had issues with VS Code getting sluggish on the full monorepo.
- Git history gets noisy — Every commit touches the monorepo, even if it only affects one app. Filtering git log by directory helps, but it's less clean than per-app repos.
- CI/CD complexity — You need to figure out which apps changed and only deploy those. Turborepo's
turbo run build --filter=[HEAD^1]helps, but setting up per-app deployment pipelines requires thought. - Dependency conflicts — If two apps need different versions of the same package, pnpm handles it via hoisting rules, but it can cause subtle issues. I hit this with React 18 vs React 19 during the dashboard upgrade.
- Initial setup overhead — Migrating existing projects into a monorepo takes time. Configuring
turbo.json, workspace references, and shared packages is a one-time cost, but it's not trivial.
When to Use a Monorepo (and When Not To)
A Turborepo monorepo makes sense when:
- You have 3+ apps that share configuration, types, or components
- You're the sole developer or a small team that works across all apps
- Apps deploy to the same infrastructure (all Cloudflare, all Vercel, etc.)
- You want atomic changes across projects (update a type, fix all consumers)
It doesn't make sense when:
- Apps are maintained by completely separate teams with different release cycles
- You have one app and no shared code — just use a regular project
- Your CI/CD pipeline can't handle selective builds (some platforms assume one repo = one deploy)
My Recommendation
If you're managing multiple websites or apps for the same organization, Turborepo + pnpm workspaces is the best developer experience I've found. The shared configuration alone saves hours of maintenance per month. The filtered builds and caching save minutes per day. And having all your code in one place makes refactoring and feature development significantly faster.
Start small: move two related projects into a monorepo with a shared tsconfig. If it feels right, add more. You don't have to migrate everything at once — Turborepo is flexible enough to grow with your needs.
Frequently Asked Questions
Is Turborepo free?
Yes, Turborepo is completely free and open-source. There's a paid Remote Caching feature (via Vercel) for sharing build caches across team members and CI, but the core tool — including local caching, task orchestration, and filtered builds — is free.
Can I use npm or yarn instead of pnpm?
Yes, Turborepo works with npm, yarn, and pnpm workspaces. I prefer pnpm for its disk efficiency (shared dependency store) and strict dependency resolution, but the monorepo benefits are the same regardless of package manager.
How do you deploy individual apps from a monorepo?
Each app has its own deployment script in the deployment/ directory. I run the script for the specific app I want to deploy — it builds that app (using turbo run build --filter=app-name) and deploys it to its Cloudflare Pages project. There's no monolithic deploy step.
Does Turborepo work with Cloudflare Pages?
Yes, but Cloudflare Pages auto-deploy (from git push) needs configuration to know which app to build. I use manual deployment scripts instead, which gives me full control over which app gets deployed when. This also avoids unnecessary deploys when unrelated apps change.
How do you handle different Node.js versions across apps?
All apps in my monorepos use the same Node.js version (>=18) specified in the root package.json engines field. If you need different versions, you'd need to use a tool like nvm or volta alongside Turborepo, which adds complexity. I'd recommend keeping all apps on the same Node.js version if possible.