Monorepo dengan Turborepo, Next.js, dan NestJS adalah arsitektur yang saya gunakan untuk proyek apa pun di mana frontend dan backend dibangun oleh tim yang sama. Type TypeScript bersama di seluruh batas menghilangkan sumber paling umum bug full-stack — ketidakcocokan bentuk API. Config ESLint dan TypeScript bersama berarti satu konfigurasi seluruh tim. Caching cerdas Turborepo berarti build hanya dijalankan ulang untuk yang berubah.
Anda bisa mengelola monorepo hanya dengan pnpm workspaces atau Yarn workspaces — itu memberi Anda hoisting paket dan referensi workspace. Turborepo menambahkan di atasnya: pipelining tugas (jalankan test hanya setelah build selesai), remote caching (bagikan artefak build di seluruh anggota tim dan CI), dan eksekusi paralel di seluruh paket. Dalam praktik, kemenangan terbesar untuk sebagian besar tim adalah konfigurasi pipeline.
Struktur Turborepo standar memiliki tiga direktori tingkat atas: apps/ (aplikasi yang bisa dijalankan — frontend Next.js, backend NestJS), packages/ (library bersama — types, komponen UI, config), dan turbo.json root. Aplikasi Next.js apps/web dan aplikasi NestJS apps/api keduanya bergantung pada packages/types, yang mengekspor semua antarmuka TypeScript dan skema Zod bersama.
my-project/ (Turborepo root)
├── turbo.json ← pipeline configuration
├── pnpm-workspace.yaml
├── package.json ← root scripts
│
├── apps/
│ ├── web/ ← Next.js frontend
│ │ ├── package.json depends on @myproject/types, @myproject/ui
│ │ └── src/
│ │ └── app/ ← Next.js App Router
│ └── api/ ← NestJS backend
│ ├── package.json depends on @myproject/types
│ └── src/
│ └── ...
│
└── packages/
├── types/ ← shared TypeScript types + Zod schemas
│ ├── package.json
│ └── src/
│ ├── user.ts export interface User {...}
│ ├── order.ts export const orderSchema = z.object({...})
│ └── index.ts export * from './user'; export * from './order'
├── ui/ ← shared React components (optional)
│ └── src/
│ └── Button.tsx
├── eslint-config/ ← shared ESLint config
└── tsconfig/ ← shared TypeScript configs
├── base.json
├── nextjs.json
└── nestjs.json
Type flow (full-stack type safety):
packages/types/src/order.ts
│ export interface CreateOrderDto
│ export const createOrderSchema = z.object(...)
├──► apps/api/ NestJS controller return type + Zod validation pipe
└──► apps/web/ Next.js fetch() response type + react-hook-form zodResolverDari menyiapkan monorepo Turborepo untuk proyek komersial di Commsult: taruh skema Zod Anda di paket packages/types bersama, bukan hanya antarmuka TypeScript. Skema Zod memberi Anda validasi runtime DAN inferensi TypeScript dari satu sumber. Backend NestJS Anda menggunakan skema Zod untuk validasi input (via custom Zod pipe), dan frontend Next.js Anda menggunakan skema yang sama untuk validasi form (via zodResolver react-hook-form). Satu skema, tiga kegunaan: definisi type, validasi API, dan validasi form.
Bootstrap dengan: pnpm dlx create-turbo@latest. Pilih contoh pnpm workspace dan pilih paket yang Anda butuhkan. turbo.json yang dihasilkan mendefinisikan pipeline tugas Anda. Konfigurasi kritis: tambahkan 'dependsOn: ["^build"]' ke tugas build Anda sehingga paket yang bergantung dibangun sebelum aplikasi yang mengonsumsi. Untuk pengembangan, jalankan turbo dev untuk memulai semua aplikasi dalam mode watch secara bersamaan.
# Bootstrap (choose pnpm + with-nestjs example or blank)
pnpm dlx create-turbo@latest
# turbo.json — pipeline configuration
{
"$schema": "https://turbo.build/schema.json",
"tasks": {
"build": {
"dependsOn": ["^build"], // build dependencies before consumers
"outputs": [".next/**", "!.next/cache/**", "dist/**"]
},
"dev": {
"cache": false,
"persistent": true // keep running (watch mode)
},
"test": {
"dependsOn": ["^build"],
"outputs": ["coverage/**"]
},
"lint": {
"outputs": []
}
}
}
# packages/types/package.json
{
"name": "@myproject/types",
"main": "./dist/index.js",
"types": "./dist/index.d.ts",
"scripts": {
"build": "tsc",
"dev": "tsc --watch"
}
}
# apps/web/package.json — consume shared types
{
"dependencies": {
"@myproject/types": "workspace:*"
}
}
# pnpm-workspace.yaml
packages:
- 'apps/*'
- 'packages/*'
# Run everything in parallel with Turborepo
pnpm turbo dev # starts Next.js (3000) + NestJS (3001) simultaneously
pnpm turbo build # builds all packages in correct dependency order
pnpm turbo test # runs tests only for changed packages
# Remote cache (connect to Vercel or self-host)
# .env
TURBO_TOKEN=your-token
TURBO_TEAM=your-team-idPaket packages/types adalah bagian paling berharga. Ia mengekspor antarmuka bersama: tipe request/response API, DTO yang cocok dengan model Prisma Anda, dan enum bersama. Backend NestJS mengimpornya untuk tipe pengembalian controller dan validasi DTO. Frontend Next.js mengimpornya untuk pengetikan respons fetch() dan skema form. Ketika Anda mengubah bentuk respons API, TypeScript segera menampilkan error di pernyataan pengembalian NestJS DAN komponen Next.js yang mengonsumsi respons.
Gotcha Turborepo paling umum: dependensi melingkar antara paket. Jika packages/ui mengimpor dari packages/types, packages/types TIDAK BOLEH mengimpor dari packages/ui. Pertahankan hierarki dependensi yang ketat: apps/ bergantung pada packages/, packages/ bisa bergantung pada packages/ lain tapi tidak pernah pada apps/. Gunakan madge untuk mengaudit grafik dependensi Anda sebelum menjadi kompleks.
Remote cache Turborepo adalah keunggulan CI/CD terbesarnya. Setelah CI run pertama, run berikutnya melewati tugas yang inputnya belum berubah. PR yang hanya mengubah aplikasi Next.js tidak akan membangun ulang aplikasi NestJS. Hubungkan ke remote cache Vercel (gratis untuk pengguna Vercel) atau self-host dengan turbo-remote-cache di infrastruktur Anda. Waktu build di GitHub Actions turun dari 8 menit menjadi 2 menit untuk sebagian besar PR setelah cache hangat.
Turborepo + pnpm workspaces adalah default saya untuk proyek apa pun di mana Next.js dan NestJS berbagi basis kode. Paket type bersama saja membenarkan pengaturan — menangkap ketidakcocokan bentuk API di compile time telah mencegah beberapa insiden produksi. Remote cache Turborepo benar-benar mengesankan di CI: cache yang hangat membuat PR bergabung dalam hitungan menit daripada 10+ menit.
Nx adalah pesaing utama Turborepo untuk alat monorepo. Nx lebih opinionated — ia menghasilkan kode, menegakkan batas modul, dan memiliki ekosistem plugin yang lebih kaya. Turborepo lebih sederhana — ia mengorkestrasikan alat yang ada tanpa menghasilkan kode atau menegakkan batas. Untuk tim kecil yang sudah menggunakan Next.js dan NestJS dengan pilihan alat mereka sendiri, kesederhanaan Turborepo adalah keunggulan. Untuk tim besar yang menginginkan batas arsitektur yang ditegakkan, Nx lebih baik diskalakan.