A Turborepo monorepo is the right architecture for any SaaS with more than one deployable application — when you have a Next.js web app, a separate API, a marketing site, and shared TypeScript types. One repository, one CI pipeline, shared code, shared tooling. No more “types are out of sync between the API and frontend.”
What Is a Monorepo?
A monorepo (monolithic repository) is a single Git repository that contains multiple projects. Instead of separate repos for your web app, API, marketing site, and component library — they all live in one repo with shared configuration and tooling.
This is the opposite of polyrepo (many repos), which most teams start with and later regret.
Turborepo is the build system that makes monorepos practical. It understands the dependency graph between your packages, caches build outputs, and only rebuilds what changed. A CI run that took 10 minutes might take 30 seconds after caching kicks in.
When a Monorepo Makes Sense
Use a monorepo when you have:
- Multiple Next.js apps (web app + marketing site + admin panel)
- A shared TypeScript types package used by both frontend and backend
- A shared component library or design system
- An API that frontend developers also modify
- 2+ developers who work across multiple parts of the system
Stick with a single repo when:
- You’re building a solo project or MVP with one application
- Your team is very small and the overhead isn’t justified yet
- You’re early enough that separation hasn’t become painful
The Standard SaaS Monorepo Structure
my-saas/
├── apps/
│ ├── web/ # Next.js app (main product)
│ ├── marketing/ # Next.js marketing site
│ └── admin/ # Internal admin panel
├── packages/
│ ├── ui/ # Shared React component library
│ ├── types/ # Shared TypeScript types
│ ├── config/ # Shared ESLint, TypeScript configs
│ └── utils/ # Shared utility functions
├── package.json # Root package.json (workspaces)
└── turbo.json # Turborepo pipeline config
The apps/ directory contains deployable applications. The packages/ directory contains shared code consumed by apps.
Setting Up Turborepo
Start with the official template:
npx create-turbo@latest my-saas --example with-tailwind
Or add Turborepo to an existing project:
npm install turbo --save-dev
turbo.json — the pipeline definition:
{
"$schema": "https://turbo.build/schema.json",
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": [".next/**", "dist/**"]
},
"dev": {
"cache": false,
"persistent": true
},
"lint": {
"outputs": []
},
"type-check": {
"outputs": []
}
}
}
The Shared Types Package
This is the highest-value package in most SaaS monorepos. Define your API types once:
// packages/types/src/index.ts
export interface User {
id: string
email: string
name: string
subscriptionStatus: 'trial' | 'active' | 'cancelled'
}
export interface ApiResponse<T> {
data: T
error?: string
}
Import them in both your Next.js app and your API:
// apps/web/app/dashboard/page.tsx
import type { User } from '@my-saas/types'
// apps/api/routes/user.ts
import type { User } from '@my-saas/types'
When you update the User type, TypeScript errors surface in every app that uses it — instantly. No more “the API sends subscription_status but the frontend expects subscriptionStatus.”
Turborepo Caching: The Main Win
Turborepo caches build outputs keyed by the inputs (source files, env variables, dependencies). If you run turbo build and nothing changed in the marketing app, it restores the cached build in seconds rather than rebuilding.
Enable remote caching to share the cache between CI and local development:
npx turbo login
npx turbo link
This cuts CI build times dramatically for large monorepos.
Deployment
Each app in apps/ deploys independently. On Vercel:
- Create a Vercel project for each app
- Set the “Root Directory” to
apps/webfor the web app,apps/marketingfor the marketing site - Vercel handles the rest, including building only the changed app
When NOT to Use Turborepo
Solo developer on a single app: The setup overhead isn’t worth it for one Next.js project. A standard Next.js repo is simpler and entirely sufficient.
Microservices at scale: For very large organisations with 50+ services, Nx or Bazel may be more appropriate. Turborepo is optimised for JavaScript/TypeScript monorepos at the 2–10 app range.
Frequently Asked Questions
Does Turborepo work with Vercel? Yes. Vercel has first-class Turborepo support including remote cache integration. Each app in your monorepo can be deployed as a separate Vercel project.
Can I use Turborepo with a non-Next.js stack? Yes. Turborepo works with any JavaScript/TypeScript build system. Express.js, Astro, SvelteKit, NestJS — any combination works.
How do I handle environment variables in a monorepo?
Each app has its own .env file. Shared environment variables (like your database URL) can be referenced from a root .env and imported in each app’s config. Use Turborepo’s globalEnv or env pipeline config to ensure environment changes invalidate the cache.
Is the learning curve steep? Turborepo’s basics take half a day to learn. The more complex workspace dependency graph scenarios take more time. The official Turborepo docs are excellent.
Should I split my design system into a separate package?
Yes, once you have 2+ apps using it. A packages/ui package containing shared components, maintained with shadcn/ui, ensures design consistency across your web app, marketing site, and admin panel.
Need a SaaS monorepo set up correctly from day one? At Whipp Studio, we architect Turborepo monorepos for SaaS products that need to scale across multiple apps. Book a free strategy call →