Home > Blog > tech

pnpm คืออะไร? Package Manager ที่เร็วและประหยัด Disk กว่า npm 2026

pnpm Package Manager Guide 2026
2026-04-16 | tech | 3500 words

pnpm (performant npm) เป็น Package Manager สำหรับ Node.js ที่เร็วกว่าและประหยัด Disk กว่า npm อย่างมาก ด้วยเทคนิค Content-Addressable Storage ที่เก็บ Package เพียงสำเนาเดียวแล้วใช้ Symlink แทนการ Copy ทำให้โปรเจกต์ 10 โปรเจกต์ที่ใช้ React ก็เก็บ React แค่ชุดเดียว

ในปี 2026 pnpm กลายเป็นทางเลือกหลักของทีม Dev ขนาดใหญ่ โดยเฉพาะ Monorepo และ CI/CD Pipeline ที่ต้องการความเร็วและประหยัดพื้นที่

pnpm vs npm vs yarn vs bun — เปรียบเทียบ

Featurenpmyarn (v4)pnpmbun
Disk Usageสูงมาก (copy ทุก project)สูง (PnP ลดได้)ต่ำมาก (content-addressable)ต่ำ
Install Speedช้าที่สุดปานกลางเร็วมากเร็วที่สุด
Monorepoworkspaces (basic)workspaces (ดี)workspaces (ดีมาก)workspaces (basic)
Strict node_modulesไม่ (hoisting)PnP modeYes (default)ไม่
Lockfilepackage-lock.jsonyarn.lockpnpm-lock.yamlbun.lockb
Peer DepsAuto-installต้อง manualStrict (ต้องระบุ)Auto-install
Ecosystemใหญ่ที่สุด (default)ใหญ่โตเร็วมากกำลังโต
Maturityสูงสุด (2010+)สูง (2016+)สูง (2017+)ปานกลาง (2022+)

Content-Addressable Storage — ทำไม pnpm ประหยัด Disk?

# npm: ทุก Project copy packages เป็นของตัวเอง
# Project A: node_modules/react (15MB)
# Project B: node_modules/react (15MB)  ← copy ซ้ำ!
# Project C: node_modules/react (15MB)  ← copy ซ้ำ!!
# Total: 45MB สำหรับ React 3 ชุด (เนื้อหาเหมือนกัน!)

# pnpm: เก็บ Package เดียวใน Content Store แล้วใช้ Hard link
# ~/.pnpm-store/react@19.0.0/... (15MB)  ← เก็บครั้งเดียว!
# Project A: node_modules/.pnpm/react@19.0.0 → Hard link ไป Store
# Project B: node_modules/.pnpm/react@19.0.0 → Hard link ไป Store
# Project C: node_modules/.pnpm/react@19.0.0 → Hard link ไป Store
# Total: ~15MB สำหรับ React ไม่ว่าจะมีกี่ Project!

# ตรวจสอบ Store location:
pnpm store path
# → C:\Users\PC\AppData\Local\pnpm\store\v3

# ตรวจสอบ Store size:
pnpm store status

Strict node_modules Structure

# npm (flat/hoisted):
# node_modules/
#   react/            ← dependencies ถูก hoist ขึ้นมา
#   react-dom/
#   lodash/           ← อาจเข้าถึงได้แม้ไม่ได้ depend!
#   some-deep-dep/    ← phantom dependency!

# pnpm (strict/non-flat):
# node_modules/
#   .pnpm/            ← ทุก Package อยู่ที่นี่
#     react@19.0.0/
#     react-dom@19.0.0/
#     lodash@4.17.21/
#   react → .pnpm/react@19.0.0/node_modules/react    ← symlink!
#   react-dom → .pnpm/react-dom@19.0.0/...           ← symlink!
#   # lodash ไม่มี symlink ที่ root ถ้าไม่ได้ depend!
#   # → ป้องกัน Phantom Dependencies!

# ข้อดี: ไม่สามารถ import Package ที่ไม่ได้ declare ใน package.json
# ข้อเสีย: บาง Package เก่าอาจพัง (แก้ด้วย shamefully-hoist)

ติดตั้ง pnpm

# วิธีที่ 1: Corepack (แนะนำ — มากับ Node.js)
corepack enable
corepack prepare pnpm@latest --activate

# วิธีที่ 2: npm
npm install -g pnpm

# วิธีที่ 3: Standalone Script
# Windows (PowerShell):
iwr https://get.pnpm.io/install.ps1 -useb | iex

# macOS/Linux:
curl -fsSL https://get.pnpm.io/install.sh | sh -

# ตรวจสอบ version:
pnpm --version
# 9.x.x (2026)

คำสั่ง pnpm ที่ใช้บ่อย

# Install ทุก dependencies จาก package.json
pnpm install
# หรือ
pnpm i

# เพิ่ม Package
pnpm add react react-dom           # dependencies
pnpm add -D typescript @types/node  # devDependencies
pnpm add -g tsx                     # global

# ลบ Package
pnpm remove lodash
pnpm rm lodash    # shorthand

# Update Package
pnpm update           # update ทุกตัวตาม semver range
pnpm update react     # update เฉพาะ react
pnpm update --latest  # update ทุกตัวเป็น latest (ไม่สน semver range)

# รัน Script
pnpm run build
pnpm run dev
pnpm start           # pnpm run start shorthand
pnpm test            # pnpm run test shorthand

# pnpm dlx (เหมือน npx)
pnpm dlx create-next-app@latest my-app
pnpm dlx degit user/repo my-project
pnpm dlx typescript --init

# ดู Dependencies Tree
pnpm list
pnpm list --depth=2
pnpm why react       # ดูว่าทำไมถึงมี react (ใครต้องการ)

# ตรวจสอบ outdated
pnpm outdated

pnpm-lock.yaml — Lockfile

# pnpm-lock.yaml คือ Lockfile ที่บันทึก exact version ของทุก dependency
# ต้อง commit เข้า Git เสมอ!
#
# ข้อดีของ pnpm-lock.yaml:
# - Readable (YAML format) ไม่เหมือน package-lock.json (JSON ยาวมาก)
# - Deterministic: install ที่ไหนก็ได้ผลเหมือนกัน
# - เร็วกว่าในการ parse

# ห้ามแก้ pnpm-lock.yaml ด้วยมือ!
# ให้ pnpm จัดการเอง

# Frozen lockfile (CI):
pnpm install --frozen-lockfile
# → ถ้า lockfile ไม่ตรงกับ package.json จะ error ทันที!

pnpm Workspace — Monorepo

# Monorepo Structure:
# my-monorepo/
#   pnpm-workspace.yaml    ← กำหนดว่า package อยู่ที่ไหน
#   package.json            ← root package.json
#   packages/
#     shared-ui/
#       package.json        ← @myorg/shared-ui
#     web-app/
#       package.json        ← @myorg/web-app
#     api-server/
#       package.json        ← @myorg/api-server

# pnpm-workspace.yaml:
packages:
  - 'packages/*'
  - 'apps/*'
  - '!**/test/**'    # exclude test directories

# Install ทั้ง Workspace:
pnpm install    # ติดตั้ง dependencies ทุก package ในครั้งเดียว

# เพิ่ม dependency ให้ package เฉพาะ:
pnpm add react --filter @myorg/web-app
pnpm add express --filter @myorg/api-server

# Internal dependency (package ใน workspace reference กัน):
# packages/web-app/package.json:
{
  "dependencies": {
    "@myorg/shared-ui": "workspace:*"    ← reference ภายใน workspace
  }
}

# รัน Script ใน package เฉพาะ:
pnpm --filter @myorg/web-app dev
pnpm --filter @myorg/api-server build

# รัน Script ทุก package:
pnpm -r run build        # recursive: build ทุก package
pnpm -r run test         # recursive: test ทุก package

# รัน Script เฉพาะ package ที่เปลี่ยน:
pnpm -r --filter "...[origin/main]" run build

Filtering Packages

# --filter patterns:
pnpm --filter @myorg/web-app build       # ชื่อ package
pnpm --filter "./packages/**" build       # glob path
pnpm --filter "...@myorg/shared-ui" build # shared-ui + ทุก package ที่ depend มัน
pnpm --filter "@myorg/web-app..." build   # web-app + ทุก dependency ของมัน
pnpm --filter "...[origin/main]" build    # เฉพาะ package ที่เปลี่ยนจาก main

# ตัวอย่าง CI/CD:
# Build เฉพาะ package ที่ถูกแก้ไข (เร็วมากใน PR):
pnpm -r --filter "...[HEAD~1]" run build
pnpm -r --filter "...[HEAD~1]" run test

pnpm overrides — แก้ปัญหา Dependency

# package.json:
{
  "pnpm": {
    "overrides": {
      "lodash": "4.17.21",              // force version
      "minimist@<1.2.6": ">=1.2.6",    // patch vulnerability
      "foo>bar": "2.0.0"                // override nested dependency
    },
    "peerDependencyRules": {
      "ignoreMissing": ["@babel/*"],     // ไม่ warn เรื่อง peer deps
      "allowAny": ["eslint"]             // อนุญาตทุก version
    }
  }
}

pnpm Store — จัดการ Global Store

# ดู Store path:
pnpm store path

# ล้าง Package ที่ไม่ได้ใช้แล้ว (orphaned):
pnpm store prune
# → ลบ Package ที่ไม่มี Project ไหนใช้แล้ว (ประหยัด Disk!)

# ตรวจสอบ Store integrity:
pnpm store status

# ย้าย Store location:
# ตั้งค่าใน .npmrc:
store-dir=/custom/path/to/pnpm-store

Migration จาก npm/yarn

# จาก npm:
# 1. ลบ node_modules และ package-lock.json
rm -rf node_modules package-lock.json

# 2. ติดตั้งด้วย pnpm
pnpm import    # อ่าน package-lock.json แล้วสร้าง pnpm-lock.yaml
# หรือ
pnpm install   # สร้าง pnpm-lock.yaml ใหม่

# จาก yarn:
rm -rf node_modules yarn.lock
pnpm import    # อ่าน yarn.lock แล้วสร้าง pnpm-lock.yaml

# ถ้ามี Package ที่พังเพราะ strict node_modules:
# .npmrc:
shamefully-hoist=true    # hoist แบบ npm (ไม่แนะนำ ใช้เป็นทางแก้ชั่วคราว)
# หรือ
public-hoist-pattern[]=*types*
public-hoist-pattern[]=*eslint*

Performance Benchmarks

Benchmark (Next.js project)npmyarn (v4)pnpmbun
Cold install (no cache)~45s~30s~18s~12s
Warm install (with cache)~15s~8s~4s~3s
With lockfile only~12s~5s~3s~2s
node_modules size~350MB~320MB~180MB~300MB
Global disk (10 projects)~3.5GB~3.2GB~500MB~3.0GB

pnpm ประหยัด Disk ที่สุด (content-addressable store) โดยเฉพาะเมื่อมีหลาย Project ใน 10 Project ที่ใช้ dependencies คล้ายกัน npm ใช้ ~3.5GB แต่ pnpm ใช้แค่ ~500MB!

pnpm + Changesets — Version Management

# Changesets ช่วยจัดการ Version ใน Monorepo
pnpm add -Dw @changesets/cli

# Initialize:
pnpm changeset init

# เมื่อแก้ไข Package:
pnpm changeset
# → เลือก Package ที่เปลี่ยน
# → เลือก Bump type (patch/minor/major)
# → เขียน Summary

# Bump versions:
pnpm changeset version
# → update package.json + CHANGELOG.md

# Publish:
pnpm changeset publish
# → publish ทุก Package ที่ version เปลี่ยน

pnpm ใน CI/CD (Caching)

# GitHub Actions:
name: CI
on: [push, pull_request]
jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: pnpm/action-setup@v4
        with:
          version: 9
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: 'pnpm'       # ← cache pnpm store อัตโนมัติ!
      - run: pnpm install --frozen-lockfile
      - run: pnpm -r run build
      - run: pnpm -r run test

# GitLab CI:
stages:
  - install
  - build
  - test

install:
  stage: install
  cache:
    key:
      files:
        - pnpm-lock.yaml
    paths:
      - .pnpm-store/
  script:
    - corepack enable
    - corepack prepare pnpm@latest --activate
    - pnpm config set store-dir .pnpm-store
    - pnpm install --frozen-lockfile

.npmrc — pnpm Configuration

# .npmrc ใน root ของ project:

# Store location (optional):
store-dir=~/.pnpm-store

# Strict peer dependencies (default in pnpm):
strict-peer-dependencies=true

# Auto-install peer deps:
auto-install-peers=true

# Hoist patterns (สำหรับ Package ที่ต้อง hoist):
public-hoist-pattern[]=*types*
public-hoist-pattern[]=*eslint*
public-hoist-pattern[]=*prettier*

# Shamefully hoist (ไม่แนะนำ):
# shamefully-hoist=true

# Node.js version:
use-node-version=22.0.0

# Registry:
registry=https://registry.npmjs.org/

# Lockfile:
lockfile=true

# Side effects cache:
side-effects-cache=true

pnpm Best Practices

Practiceทำไม
ใช้ Corepack enableจัดการ pnpm version ตาม project (packageManager field)
Commit pnpm-lock.yamlDeterministic builds ทุก environment ได้ผลเหมือนกัน
CI ใช้ --frozen-lockfileป้องกัน lockfile ไม่ตรงกับ package.json
ใช้ workspace:* สำหรับ internal packagesReference ภายใน monorepo แบบ live (ไม่ต้อง publish)
pnpm store prune เป็นระยะลบ Package ที่ไม่ใช้แล้ว ประหยัด Disk
ไม่ใช้ shamefully-hoistปล่อยให้ pnpm บังคับ strict dependencies (ดีกว่า)
ใช้ --filter ใน CIBuild/Test เฉพาะ package ที่เปลี่ยน (เร็วมาก)
ตั้ง packageManager ใน package.jsonบังคับทุกคนในทีมใช้ pnpm version เดียวกัน
เริ่มต้น: corepack enable && pnpm init แล้วเริ่มใช้ pnpm add/install/run แทน npm ได้ทันที Migration จาก npm ง่ายมาก แค่ลบ node_modules + package-lock.json แล้วรัน pnpm install

สรุป

pnpm เป็น Package Manager ที่ เร็วกว่าและประหยัด Disk กว่า npm อย่างมาก ด้วย Content-Addressable Storage ที่เก็บ Package เพียงครั้งเดียว ใช้ Hard link แทนการ Copy ทำให้ 10 Project ใช้ Disk เท่ากับ 1 Project เหมาะกับ Monorepo ที่มีหลาย Package ใน Workspace เดียว รองรับ Filtering สำหรับ CI/CD ที่ Build/Test เฉพาะ Package ที่เปลี่ยน

pnpm ยังมี Strict node_modules ที่ป้องกัน Phantom Dependencies ทำให้ Code ที่เขียนถูกต้องจริง ๆ ไม่ใช่บังเอิญใช้ได้เพราะ hoisting ถ้าทีมยังใช้ npm อยู่ ลองเปลี่ยนมา pnpm จะเห็นความแตกต่างทันที


Back to Blog | iCafe Forex | SiamLanCard | Siam2R