Home > Blog > tech

Monorepo คืออะไร? สอนใช้ Turborepo, Nx สำหรับจัดการ Multi-Package Project 2026

monorepo turborepo guide
Monorepo Turborepo Guide 2026
2026-04-11 | tech | 3500 words

ถ้าคุณเคยทำงานกับโปรเจกต์ที่มีหลาย Package หลาย Service หรือหลาย App ที่ต้องแชร์โค้ดร่วมกัน คุณน่าจะเคยเจอปัญหาเหล่านี้: แก้โค้ด Shared Library แล้วต้องไป Publish อัปเดตทีละ Repo, เวอร์ชันไม่ตรงกัน หรือ CI/CD Pipeline ที่ซับซ้อนจนจัดการไม่ไหว ทั้งหมดนี้คือเหตุผลที่ Monorepo เกิดขึ้นมา และในปี 2026 เครื่องมืออย่าง Turborepo และ Nx ทำให้การจัดการ Monorepo เป็นเรื่องง่ายกว่าที่เคย

บทความนี้จะพาคุณเข้าใจ Monorepo ตั้งแต่แนวคิดพื้นฐาน เปรียบเทียบกับ Polyrepo ไปจนถึงการตั้งค่า Turborepo และ Nx แบบ Step-by-step พร้อม CI/CD Pipeline ที่ใช้งานได้จริงในทีม

Monorepo คืออะไร?

Monorepo (Monolithic Repository) คือแนวทางการจัดการ Source Code ที่เก็บหลาย Package, หลาย Application หรือหลาย Service ไว้ใน Git Repository เดียวกัน แทนที่จะแยกเป็นหลาย Repo ตัวอย่างเช่น คุณอาจมี Frontend App, Backend API, Shared UI Components และ Utility Functions ทั้งหมดอยู่ใน Repo เดียว

บริษัทเทคโนโลยีชั้นนำหลายแห่งใช้ Monorepo ในการจัดการโค้ดของตนเอง เช่น Google ที่เก็บโค้ดทั้งหมดไว้ใน Repo เดียวกว่าสองพันล้านบรรทัด, Meta (Facebook) ที่ใช้ Monorepo สำหรับ Web Frontend ทั้งหมด, Microsoft ที่เก็บ Windows Source Code ใน Monorepo ขนาดมหาศาล รวมถึง Vercel ที่เป็นผู้สร้าง Turborepo เองก็ใช้ Monorepo ในการพัฒนาผลิตภัณฑ์ของตัวเอง

โครงสร้าง Monorepo ทั่วไป

my-monorepo/
├── apps/
│   ├── web/              # Next.js Frontend
│   ├── mobile/           # React Native App
│   └── api/              # Express/NestJS Backend
├── packages/
│   ├── ui/               # Shared UI Components
│   ├── utils/            # Shared Utilities
│   ├── config/           # Shared ESLint, TS Config
│   └── database/         # Prisma Schema & Client
├── turbo.json            # Turborepo Config
├── package.json          # Root Package
└── pnpm-workspace.yaml   # Workspace Config

Monorepo vs Polyrepo: เปรียบเทียบให้ชัด

ก่อนจะตัดสินใจใช้ Monorepo คุณต้องเข้าใจความแตกต่างระหว่าง Monorepo กับ Polyrepo (การแยก Repo แบบดั้งเดิม) ให้ชัดเจนก่อน เพราะแต่ละแนวทางมีข้อดีข้อเสียที่แตกต่างกันอย่างสิ้นเชิง

หัวข้อMonorepoPolyrepo
Code Sharingแชร์โค้ดง่าย Import ตรงจาก Packageต้อง Publish แล้ว Install ทีละ Repo
Atomic Commitsแก้หลาย Package ใน Commit เดียวต้อง Commit แยกแต่ละ Repo
CI/CDPipeline เดียว แต่ต้องฉลาดพอจะ Build เฉพาะที่เปลี่ยนแต่ละ Repo มี Pipeline แยก ง่ายแต่ซ้ำซ้อน
Dependency Managementเวอร์ชันตรงกันเสมอ ไม่มี Version Mismatchอาจเจอปัญหาเวอร์ชันไม่ตรงกัน
Repo Sizeอาจใหญ่มากจนช้า ต้องใช้ Sparse Checkoutแต่ละ Repo เล็ก Clone เร็ว
Permissionsควบคุมสิทธิ์ระดับ Folder ยากกว่าแยกสิทธิ์ตาม Repo ได้ง่าย
Toolingต้องใช้ Turborepo/Nx ช่วยใช้เครื่องมือมาตรฐานได้เลย

ข้อดีของ Monorepo ที่ทำให้ทีมเลือกใช้

การใช้ Monorepo มีข้อได้เปรียบหลายประการที่ทำให้ทีมพัฒนาขนาดกลางถึงใหญ่เลือกใช้แนวทางนี้มากขึ้นเรื่อยๆ ในปี 2026

1. Code Sharing ที่ราบรื่น

แทนที่จะต้อง Publish Package ไปยัง npm Registry แล้วค่อย Install ในแต่ละ Repo คุณสามารถ Import โค้ดจาก Package อื่นได้โดยตรงราวกับเป็นโค้ดใน Folder เดียวกัน เมื่อแก้ไข Shared Component แล้ว ทุก App ที่ใช้จะได้รับการเปลี่ยนแปลงทันทีโดยไม่ต้อง Publish ใหม่

2. Atomic Commits ข้าม Package

สมมติคุณต้องเปลี่ยน API Response Format ใน Backend และอัปเดต Frontend ให้รองรับ Format ใหม่ ใน Monorepo คุณทำได้ใน Commit เดียว ไม่ต้องเปิด PR สอง Repo แล้วพยายาม Merge ให้พร้อมกัน ซึ่งเป็นฝันร้ายที่นักพัฒนาหลายคนคงเคยประสบมาก่อน

3. Unified CI/CD Pipeline

มี Pipeline เดียวที่ดูแลทุกอย่าง เมื่อรวมกับเครื่องมืออย่าง Turborepo หรือ Nx ที่สามารถตรวจจับได้ว่า Package ไหนถูกแก้ไขและ Build เฉพาะส่วนที่เกี่ยวข้อง ทำให้ CI เร็วพอๆ กับ Polyrepo แต่จัดการง่ายกว่ามาก

4. Consistent Tooling

ESLint Config, TypeScript Config, Prettier Config ทั้งหมดแชร์จากที่เดียว ไม่ต้องก็อปไปวางทุก Repo แล้วพยายาม Sync ให้ตรงกัน เมื่ออัปเดต Config ที่เดียวก็มีผลทุกที่ทันที

ความท้าทายของ Monorepo

แม้ว่า Monorepo จะมีข้อดีมากมาย แต่ก็มาพร้อมกับความท้าทายที่ต้องเตรียมรับมือ

Build Time ที่อาจนานขึ้น

เมื่อมีหลาย Package ในที่เดียว ถ้าไม่มีเครื่องมือที่ฉลาดพอ CI อาจ Build ทุกอย่างทุกครั้ง แม้ว่าจะแก้ไขแค่ไฟล์เดียว นี่คือเหตุผลหลักที่ Turborepo และ Nx ถูกสร้างขึ้นมา เพื่อแก้ปัญหานี้ด้วย Caching และ Affected Analysis

Permission Management

ใน Polyrepo คุณสามารถกำหนดสิทธิ์เข้าถึงแต่ละ Repo ได้ง่ายๆ ผ่าน GitHub Settings แต่ใน Monorepo ทุกคนเห็นทุกอย่าง ต้องใช้ CODEOWNERS File และ Branch Protection Rules เข้ามาช่วย

Repository Size

เมื่อเวลาผ่านไป Monorepo อาจมีขนาดใหญ่มากจน git clone ช้า ทางแก้คือใช้ git sparse-checkout หรือ git shallow clone เพื่อดึงเฉพาะส่วนที่ต้องการ

Turborepo คืออะไร?

Turborepo เป็น High-Performance Build System สำหรับ JavaScript/TypeScript Monorepo ที่สร้างโดย Jared Palmer และถูก Vercel ซื้อไปในปี 2021 ปัจจุบันเป็นหนึ่งในเครื่องมือยอดนิยมที่สุดสำหรับจัดการ Monorepo โดยเฉพาะในระบบนิเวศของ Next.js และ React

ฟีเจอร์เด่นของ Turborepo

ติดตั้งและตั้งค่า Turborepo

# สร้าง Monorepo ใหม่ด้วย Turborepo
npx create-turbo@latest my-monorepo

# หรือเพิ่ม Turborepo เข้าโปรเจกต์ที่มีอยู่แล้ว
npm install turbo --save-dev

turbo.json Configuration

{
  "$schema": "https://turbo.build/schema.json",
  "globalDependencies": ["**/.env.*local"],
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**", ".next/**", "!.next/cache/**"]
    },
    "lint": {
      "dependsOn": ["^build"]
    },
    "test": {
      "dependsOn": ["build"],
      "outputs": [],
      "inputs": ["src/**/*.tsx", "src/**/*.ts", "test/**/*.ts"]
    },
    "dev": {
      "cache": false,
      "persistent": true
    },
    "type-check": {
      "dependsOn": ["^build"]
    }
  }
}
dependsOn: ["^build"] หมายความว่าก่อนจะ Build Package นี้ ต้อง Build Package ที่เป็น Dependency (ใน Workspace) ให้เสร็จก่อน เครื่องหมาย ^ หมายถึง Upstream Dependencies

pnpm-workspace.yaml

# pnpm-workspace.yaml
packages:
  - "apps/*"
  - "packages/*"

Root package.json

{
  "name": "my-monorepo",
  "private": true,
  "scripts": {
    "build": "turbo run build",
    "dev": "turbo run dev",
    "lint": "turbo run lint",
    "test": "turbo run test",
    "type-check": "turbo run type-check"
  },
  "devDependencies": {
    "turbo": "^2.4.0"
  },
  "packageManager": "pnpm@9.15.0"
}

Remote Caching กับ Vercel

หนึ่งในฟีเจอร์ที่ทรงพลังที่สุดของ Turborepo คือ Remote Caching ซึ่งช่วยให้ทีมทั้งทีมแชร์ Build Cache ร่วมกันได้ เมื่อคนหนึ่ง Build Package แล้ว คนอื่นไม่ต้อง Build ซ้ำอีก แค่ดึง Cache มาใช้ได้เลย

# เชื่อมต่อกับ Vercel Remote Cache
npx turbo login
npx turbo link

# ตอนนี้ทุกคนในทีมจะแชร์ Cache ร่วมกัน
# Build ครั้งแรกอาจใช้เวลา 2 นาที
# Build ครั้งต่อไป (Cache hit) อาจใช้เวลาแค่ 5 วินาที

# ดู Cache status
turbo run build --dry-run
Self-hosted Remote Cache: ถ้าไม่ต้องการใช้ Vercel Cloud สามารถตั้ง Self-hosted Remote Cache ได้ด้วย turborepo-remote-cache Server ที่รองรับ S3-compatible Storage เช่น MinIO หรือ Cloudflare R2

Nx คืออะไร?

Nx (สร้างโดย Nrwl) เป็น Smart Build System และ Monorepo Tool ที่เน้นการจัดการโปรเจกต์ขนาดใหญ่ มีมาก่อน Turborepo และมีฟีเจอร์ครบกว่า เหมาะสำหรับทีมที่ต้องการเครื่องมือที่มี Built-in Support สำหรับหลาย Framework

ฟีเจอร์เด่นของ Nx

ติดตั้งและใช้ Nx

# สร้าง Nx Workspace ใหม่
npx create-nx-workspace@latest my-workspace

# เพิ่ม Nx เข้าโปรเจกต์ที่มีอยู่
npx nx@latest init

# รัน Task
npx nx run my-app:build
npx nx run-many --target=build --all
npx nx affected --target=test  # เฉพาะที่ถูกกระทบ

# ดู Project Graph
npx nx graph

nx.json Configuration

{
  "$schema": "https://nx.dev/reference/nx-json",
  "tasksRunnerOptions": {
    "default": {
      "runner": "nx/tasks-runners/default",
      "options": {
        "cacheableOperations": ["build", "lint", "test", "e2e"]
      }
    }
  },
  "targetDefaults": {
    "build": {
      "dependsOn": ["^build"],
      "inputs": ["production", "^production"],
      "cache": true
    },
    "test": {
      "inputs": ["default", "^production"],
      "cache": true
    }
  },
  "namedInputs": {
    "default": ["{projectRoot}/**/*", "sharedGlobals"],
    "production": ["default", "!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)"],
    "sharedGlobals": []
  }
}

Turborepo vs Nx: เลือกตัวไหนดี?

นี่คือคำถามที่นักพัฒนาหลายคนสงสัย มาเปรียบเทียบกันอย่างละเอียดเพื่อช่วยในการตัดสินใจ

หัวข้อTurborepoNx
Learning Curveง่าย ตั้งค่าน้อย เรียนรู้เร็วซับซ้อนกว่า มีฟีเจอร์เยอะกว่า
Configurationturbo.json ไฟล์เดียวnx.json + project.json หลายไฟล์
CachingLocal + Vercel Remote CacheLocal + Nx Cloud Remote Cache
Affected Analysisไม่มี Built-in ต้องใช้ --filterมี nx affected ที่ทรงพลัง
Code Generationไม่มีมี Generators ครบ
Plugin Ecosystemน้อย เน้น Minimalเยอะมาก ครบทุก Framework
Project Graphไม่มี Visual Toolมี nx graph ที่สวยงาม
Language SupportJavaScript/TypeScript เท่านั้นJS/TS, Go, Rust, Java และอื่นๆ
เหมาะกับทีมเล็ก-กลาง ต้องการความเรียบง่ายทีมใหญ่ Enterprise ต้องการเครื่องมือครบ
คำแนะนำ: ถ้าคุณเพิ่งเริ่มต้นกับ Monorepo และใช้ Next.js/React เป็นหลัก ให้เริ่มจาก Turborepo เพราะง่ายกว่า ถ้าต้องการ Affected Analysis หรือมี Multi-language Project ให้เลือก Nx

Workspace Tools: npm, pnpm, yarn

ทั้ง Turborepo และ Nx ไม่ได้จัดการ Dependency เอง แต่ใช้ Workspace Feature ของ Package Manager แทน ทำให้คุณต้องเลือก Package Manager ที่รองรับ Workspaces ด้วย

pnpm Workspaces (แนะนำ)

# pnpm-workspace.yaml
packages:
  - "apps/*"
  - "packages/*"

# ติดตั้ง Dependency สำหรับ Package เฉพาะ
pnpm add lodash --filter @myorg/utils

# รัน Script ใน Package เฉพาะ
pnpm --filter @myorg/web dev

# ติดตั้ง Dependency ทั้งหมด
pnpm install

npm Workspaces

// package.json
{
  "workspaces": ["apps/*", "packages/*"]
}

// ติดตั้ง Dependency สำหรับ Package เฉพาะ
npm install lodash -w packages/utils

yarn Workspaces

// package.json
{
  "workspaces": ["apps/*", "packages/*"]
}

// ติดตั้ง Dependency สำหรับ Package เฉพาะ
yarn workspace @myorg/utils add lodash
ทำไมต้อง pnpm? pnpm ใช้ Content-addressable Storage ที่ทำให้ไม่ต้อง Download Package ซ้ำ ประหยัดพื้นที่และเร็วกว่า npm/yarn มาก โดยเฉพาะใน Monorepo ที่มีหลาย Package ที่ใช้ Dependency เดียวกัน

Internal Packages vs Published Packages

ใน Monorepo มี Package สองแบบที่ต้องเข้าใจ

Internal Packages

Package ที่ใช้ภายใน Monorepo เท่านั้น ไม่ได้ Publish ไป npm Registry ตั้งค่าง่ายมากเพราะไม่ต้อง Build ก่อน Import ได้ ใช้ "main" ชี้ไปที่ Source Code ตรงๆ หรือใช้ Bundler ของ App ที่ Consume มัน Transpile ให้

// packages/ui/package.json
{
  "name": "@myorg/ui",
  "version": "0.0.0",
  "private": true,
  "main": "./src/index.ts",
  "types": "./src/index.ts",
  "exports": {
    ".": "./src/index.ts",
    "./button": "./src/button.tsx",
    "./card": "./src/card.tsx"
  }
}

// apps/web/package.json — Import ได้เลย
{
  "dependencies": {
    "@myorg/ui": "workspace:*"
  }
}

Published Packages

Package ที่ต้อง Publish ไป npm Registry เพื่อให้โปรเจกต์ภายนอกใช้ ต้อง Build เป็น JavaScript ก่อน Publish และต้องจัดการ Versioning อย่างเป็นระบบ

// packages/sdk/package.json
{
  "name": "@myorg/sdk",
  "version": "1.2.3",
  "main": "./dist/index.js",
  "types": "./dist/index.d.ts",
  "files": ["dist"],
  "scripts": {
    "build": "tsup src/index.ts --format cjs,esm --dts"
  }
}

Changesets สำหรับ Versioning

Changesets เป็นเครื่องมือที่ช่วยจัดการ Versioning และ Changelog ใน Monorepo ได้อย่างเป็นระบบ แทนที่จะต้องจำว่า Package ไหนต้องขึ้น Version เท่าไหร่ Changesets จะช่วยจัดการให้

# ติดตั้ง Changesets
pnpm add -D -w @changesets/cli @changesets/changelog-github

# เริ่มต้นใช้งาน
pnpm changeset init

# สร้าง Changeset เมื่อมีการเปลี่ยนแปลง
pnpm changeset
# → เลือก Package ที่เปลี่ยน
# → เลือก Semver bump (patch/minor/major)
# → เขียน Summary ของการเปลี่ยนแปลง

# Apply Changesets → ขึ้น Version + Generate Changelog
pnpm changeset version

# Publish ไป npm
pnpm changeset publish

.changeset/config.json

{
  "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
  "changelog": ["@changesets/changelog-github", { "repo": "myorg/monorepo" }],
  "commit": false,
  "fixed": [],
  "linked": [["@myorg/ui", "@myorg/utils"]],
  "access": "public",
  "baseBranch": "main",
  "updateInternalDependencies": "patch"
}

Shared Packages: UI, Utils, Config

หัวใจของ Monorepo คือ Shared Packages ที่ทุก App สามารถใช้ร่วมกันได้ มาดูตัวอย่างการสร้าง Shared Package แต่ละประเภท

Shared UI Package

// packages/ui/src/button.tsx
import React from "react";

interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
  variant?: "primary" | "secondary" | "danger";
  size?: "sm" | "md" | "lg";
}

export function Button({ variant = "primary", size = "md", children, ...props }: ButtonProps) {
  return (
    <button className={`btn btn-${variant} btn-${size}`} {...props}>
      {children}
    </button>
  );
}

// packages/ui/src/index.ts
export { Button } from "./button";
export { Card } from "./card";
export { Input } from "./input";

Shared Config Package

// packages/config/eslint-preset.js
module.exports = {
  extends: ["next", "turbo", "prettier"],
  rules: {
    "@next/next/no-html-link-for-pages": "off",
  },
  parserOptions: {
    babelOptions: {
      presets: [require.resolve("next/babel")],
    },
  },
};

// apps/web/.eslintrc.js — ใช้ Config จาก Package
module.exports = {
  root: true,
  extends: ["@myorg/config/eslint-preset"],
};

Shared TypeScript Config

// packages/config/tsconfig.base.json
{
  "compilerOptions": {
    "target": "ES2022",
    "lib": ["ES2022", "DOM", "DOM.Iterable"],
    "module": "ESNext",
    "moduleResolution": "bundler",
    "strict": true,
    "esModuleInterop": true,
    "skipLibCheck": true,
    "forceConsistentCasingInFileNames": true,
    "resolveJsonModule": true,
    "isolatedModules": true,
    "incremental": true
  }
}

// apps/web/tsconfig.json
{
  "extends": "@myorg/config/tsconfig.base.json",
  "compilerOptions": {
    "jsx": "preserve",
    "plugins": [{ "name": "next" }]
  },
  "include": ["next-env.d.ts", "src/**/*.ts", "src/**/*.tsx"],
  "exclude": ["node_modules"]
}

CI/CD สำหรับ Monorepo (GitHub Actions)

การตั้งค่า CI/CD สำหรับ Monorepo ต้องฉลาดพอที่จะ Build เฉพาะสิ่งที่เปลี่ยนแปลง ไม่งั้น CI จะช้ามากเมื่อ Repo โตขึ้น

# .github/workflows/ci.yml
name: CI
on:
  push:
    branches: [main]
  pull_request:
    branches: [main]

env:
  TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
  TURBO_TEAM: ${{ secrets.TURBO_TEAM }}

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 2  # สำหรับ turbo --filter

      - uses: pnpm/action-setup@v4
        with:
          version: 9

      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: "pnpm"

      - run: pnpm install --frozen-lockfile

      # Turborepo จะใช้ Remote Cache อัตโนมัติ
      - run: pnpm turbo run lint test build

      # หรือถ้าใช้ Nx
      # - run: npx nx affected --target=lint --base=origin/main
      # - run: npx nx affected --target=test --base=origin/main
      # - run: npx nx affected --target=build --base=origin/main
TURBO_TOKEN และ TURBO_TEAM: ตั้งค่าใน GitHub Secrets เพื่อให้ CI ใช้ Remote Cache ของ Vercel ได้ วิธีนี้ทำให้ CI ครั้งที่สอง เร็วขึ้นอย่างมากเพราะไม่ต้อง Build Package ที่ไม่เปลี่ยนแปลง

Task Dependencies และ Pipeline

การเข้าใจ Task Dependencies เป็นสิ่งสำคัญมากในการใช้งาน Turborepo ให้มีประสิทธิภาพ เพราะถ้าตั้ง Pipeline ผิด อาจ Build ล้มเหลวหรือช้ากว่าที่ควร

// turbo.json — ตัวอย่าง Pipeline ที่ซับซ้อน
{
  "pipeline": {
    "build": {
      "dependsOn": ["^build"],
      "outputs": ["dist/**"],
      "inputs": ["src/**", "package.json", "tsconfig.json"]
    },
    "test": {
      "dependsOn": ["build"],
      "outputs": ["coverage/**"],
      "inputs": ["src/**", "test/**"]
    },
    "lint": {
      "outputs": []
    },
    "deploy": {
      "dependsOn": ["build", "test", "lint"],
      "outputs": [],
      "cache": false
    },
    "db:migrate": {
      "cache": false
    }
  }
}

ลำดับการทำงาน: เมื่อรัน turbo run deploy Turborepo จะวิเคราะห์ Pipeline แล้วรัน lint (ไม่มี Dependency) ก่อนพร้อมกับ build ของ Package ที่ไม่ขึ้นกับใคร จากนั้น build Package ที่ต้องรอ แล้ว test (ต้องรอ build) แล้วสุดท้ายคือ deploy ที่ต้องรอทุกอย่างเสร็จ ทั้งหมดนี้เกิดขึ้นอัตโนมัติ

Code Ownership ด้วย CODEOWNERS

ใน Monorepo ที่มีหลายทีมทำงานร่วมกัน CODEOWNERS File ช่วยกำหนดว่าใครเป็นเจ้าของโค้ดส่วนไหน เมื่อมี PR ที่แก้ไขโค้ดในส่วนที่มีเจ้าของ GitHub จะเพิ่ม Reviewer อัตโนมัติ

# .github/CODEOWNERS

# ทีม Frontend เป็นเจ้าของ Web App
apps/web/                    @myorg/frontend-team
packages/ui/                 @myorg/frontend-team

# ทีม Backend เป็นเจ้าของ API
apps/api/                    @myorg/backend-team
packages/database/           @myorg/backend-team

# ทีม Platform เป็นเจ้าของ Config และ CI
packages/config/             @myorg/platform-team
.github/                     @myorg/platform-team
turbo.json                   @myorg/platform-team

# Shared Utils ต้องได้รับ Review จากทั้งสองทีม
packages/utils/              @myorg/frontend-team @myorg/backend-team

เมื่อ Monorepo เป็น Overkill

Monorepo ไม่ใช่คำตอบสำหรับทุกสถานการณ์ มีหลายกรณีที่ Polyrepo เหมาะกว่า และการใช้ Monorepo โดยไม่จำเป็นอาจสร้างปัญหามากกว่าแก้ปัญหา

ไม่ควรใช้ Monorepo เมื่อ:

ควรใช้ Monorepo เมื่อ:

Turborepo Filter และ Scoped Tasks

เมื่อ Monorepo มีหลาย Package บางทีคุณต้องการรัน Task เฉพาะบาง Package ไม่ใช่ทั้งหมด Turborepo มี --filter Flag ที่ทรงพลังมาก

# รัน build เฉพาะ web app
turbo run build --filter=@myorg/web

# รัน build เฉพาะ web app และ Dependencies ของมัน
turbo run build --filter=@myorg/web...

# รัน test เฉพาะ Package ที่เปลี่ยนตั้งแต่ main
turbo run test --filter=...[origin/main]

# รัน lint เฉพาะ Package ใน apps/ Directory
turbo run lint --filter="./apps/*"

# Combine filters
turbo run build --filter=@myorg/web --filter=@myorg/api

Docker กับ Monorepo (Pruned Subsets)

เมื่อต้อง Deploy App จาก Monorepo ด้วย Docker คุณไม่ต้องการ COPY ทั้ง Monorepo เข้า Image เพราะจะทำให้ Image ใหญ่มาก Turborepo มีคำสั่ง turbo prune ที่ช่วยสร้าง Subset ที่มีเฉพาะ Package ที่จำเป็น

# Dockerfile
FROM node:22-alpine AS base

FROM base AS builder
RUN apk add --no-cache libc6-compat
WORKDIR /app
RUN npm install -g turbo pnpm

COPY . .
RUN turbo prune @myorg/web --docker

FROM base AS installer
WORKDIR /app

COPY --from=builder /app/out/json/ .
COPY --from=builder /app/out/pnpm-lock.yaml ./pnpm-lock.yaml
RUN pnpm install --frozen-lockfile

COPY --from=builder /app/out/full/ .
RUN pnpm turbo run build --filter=@myorg/web

FROM base AS runner
WORKDIR /app
RUN addgroup --system --gid 1001 nodejs
RUN adduser --system --uid 1001 nextjs

COPY --from=installer /app/apps/web/.next/standalone ./
COPY --from=installer /app/apps/web/.next/static ./apps/web/.next/static
COPY --from=installer /app/apps/web/public ./apps/web/public

USER nextjs
EXPOSE 3000
CMD ["node", "apps/web/server.js"]

Best Practices สำหรับ Monorepo ในปี 2026

  1. ใช้ pnpm เป็น Package Manager เพราะเร็วและประหยัดพื้นที่กว่า npm/yarn ใน Monorepo
  2. ตั้ง Remote Caching ตั้งแต่วันแรก เพื่อให้ทุกคนในทีมได้ประโยชน์จาก Cache ร่วมกัน
  3. กำหนด inputs และ outputs ใน turbo.json ให้ถูกต้อง เพื่อให้ Cache แม่นยำ
  4. ใช้ CODEOWNERS เพื่อกำหนดความรับผิดชอบและ Auto-assign Reviewers
  5. แยก Internal Packages ที่ไม่จำเป็นต้อง Build ออกจาก Published Packages ที่ต้อง Build
  6. ตั้ง Changeset Bot ใน CI เพื่อเตือนเมื่อ PR ไม่มี Changeset สำหรับ Published Packages
  7. ใช้ Turborepo --dry-run เพื่อดูว่า Task ไหนจะถูกรันก่อน Commit จริง
  8. ตั้ง Type Checking แยกเป็น Task ต่างหากจาก Build เพื่อให้ Cache ทำงานได้ดีกว่า

สรุป

Monorepo เป็นแนวทางที่ทรงพลังสำหรับการจัดการ Multi-Package Project โดยเฉพาะเมื่อมีหลาย App ที่แชร์โค้ดร่วมกัน ในปี 2026 เครื่องมืออย่าง Turborepo และ Nx ทำให้ความท้าทายดั้งเดิมของ Monorepo เช่น Build Time ที่นาน หรือ CI ที่ซับซ้อน กลายเป็นเรื่องที่จัดการได้ง่ายด้วย Caching, Parallel Execution และ Affected Analysis

สำหรับทีมที่เพิ่งเริ่มต้นแนะนำให้ลอง Turborepo ก่อนเพราะตั้งค่าน้อยและเรียนรู้เร็ว จากนั้นถ้าต้องการฟีเจอร์ขั้นสูงอย่าง Affected Commands หรือ Code Generators ค่อยย้ายไป Nx การจัดการ Monorepo ที่ดีจะช่วยให้ทีมของคุณทำงานเร็วขึ้น ลดข้อผิดพลาด และสร้างผลิตภัณฑ์ที่มีคุณภาพสูงขึ้นในที่สุด


Back to Blog | iCafe Forex | SiamLanCard | Siam2R