A Turborepo with a marketing site, a docs site, and a web app is a normal setup in 2026. Vercel handles it, but only if you configure the root directory, ignored builds, and shared packages correctly. The wrong combination either rebuilds everything on every push (slow and expensive) or refuses to find your shared UI library at all.
Background
A Vercel project deploys exactly one app. For a monorepo with N apps, you create N Vercel projects, each pointing to a different directory. Turbo helps by caching builds and skipping unaffected apps. The friction is at the boundary: telling Vercel where each app lives, what to build, and when to skip.
How to tell
- Pushing a tiny edit to one app triggers builds on all three projects.
- Vercel cannot find
@workspace/uiand fails with “Module not found” in the build log. - The wrong app is being deployed because Vercel followed the wrong build command from the repo root.
- Your
turbo.jsonworks locally but Vercel ignores the cache entirely.
Quick verdict
Put each app under apps/, create one Vercel project per app, set Root Directory to apps/<name>, use turbo as the build wrapper, and add an ignoreCommand to skip builds that do not touch the app.
Project structure that works
A typical layout:
my-monorepo/
├── apps/
│ ├── www/ → marketing (Astro)
│ ├── docs/ → docs (Next.js)
│ └── app/ → web app (Next.js)
├── packages/
│ ├── ui/ → shared React components
│ ├── config-tsconfig/ → shared tsconfig
│ └── eslint-config/ → shared lint
├── turbo.json
├── package.json → workspaces: ["apps/*", "packages/*"]
└── pnpm-workspace.yaml → if using pnpm
Each apps/<name>/package.json declares @workspace/ui as a normal dependency ("workspace:*" for pnpm, "*" for npm/yarn workspaces).
Configure Vercel per app
Settings → General for each Vercel project:
- Root Directory:
apps/www(orapps/docs, etc.). This is the most-skipped step and the cause of most “module not found” errors. - Build Command:
cd ../.. && pnpm turbo run build --filter=www(replacepnpmwithnpm/yarnas needed). The--filteris what makes Turbo build only this app and its dependencies. - Install Command: leave blank — Vercel auto-detects pnpm / npm / yarn and runs the workspace install from the repo root.
- Output Directory: framework default (Astro:
dist, Next.js:.next). - Node version: pin via
engines.nodein the rootpackage.json.
Skip unaffected builds with Ignored Build Step
The single biggest cost saver in a monorepo on Vercel. In each project, Settings → Git → Ignored Build Step:
npx turbo-ignore www
Replace www with the app name. turbo-ignore exits 0 (skip build) if no files in that app’s dependency graph changed since the last successful deploy. So a docs-only edit no longer rebuilds www.
For a non-Turbo monorepo, the manual version:
git diff HEAD^ HEAD --quiet ./ ../../packages/ui ../../packages/config-tsconfig
Vercel skips the build if this exits 0.
Shared packages without a publish step
Two patterns work; pick one and stick to it:
- Transpile-on-build (Next.js). Use
transpilePackagesinnext.config.js:
/** @type {import('next').NextConfig} */
module.exports = {
transpilePackages: ['@workspace/ui', '@workspace/config-tsconfig'],
};
- Pre-built packages. Each package has a
buildscript that emits todist/, and the package’spackage.jsonpointsmain/typesat the built output.turbobuilds dependencies before dependents because ofpipeline.build.dependsOn = ["^build"].
Pattern 1 is simpler for content sites. Pattern 2 scales better when the package is also published to npm.
Common mistakes
- Leaving Root Directory at
/and wondering why the wrong app builds — every project must point to its own subdir. - Using
npm installat the project root in the build command instead of letting Vercel detect the workspace — breaks pnpm / yarn workspaces. - Forgetting
--filterin the build command — Turbo builds every app on every deploy, defeating the point of a monorepo. - Skipping
turbo-ignoreand paying for full rebuilds on docs typos. - Not pinning Node in the root
package.json— Vercel may pick different Node versions across projects. - Putting environment variables in only one project when two apps need them — env vars are scoped per Vercel project.
FAQ
- Do I need Turbo to deploy a monorepo on Vercel?: No. Vercel supports npm / yarn / pnpm workspaces directly. Turbo is for caching and
turbo-ignore. For under 3 apps, plain workspaces are often enough. - Can one repo deploy to one Vercel project with multiple frameworks?: No. One project = one framework / build. Use multiple projects.
- What about Nx instead of Turbo?: Works the same way: set Root Directory per app, run
nx build <app>in the build command, use Nx’s affected commands for ignored builds. - How do preview deploys work across projects?: Each project gets its own preview URL per PR. You can configure your PR template to list all three URLs, or use the Vercel comment for each project.
- Does Vercel cache
node_modulesacross projects in the same monorepo?: Each project has its own cache. Turbo’s remote cache helps across projects if you link them all to the same Turbo remote.