Changesets으로 모노레포 패키지 버전 관리와 npm 배포 자동화

프론트엔드

Changesets모노레포npm 배포버전 관리Turborepo

이 글은 누구를 위한 것인가

  • 모노레포에서 여러 패키지의 버전을 일관되게 관리하려는 팀
  • npm에 패키지를 배포할 때 CHANGELOG와 버전을 자동화하려는 개발자
  • Changesets를 처음 도입하는 팀을 위한 설정 가이드가 필요한 개발자

들어가며

모노레포에서 패키지 버전을 수동으로 관리하면 @myapp/ui v1.2.3이 @myapp/core v2.1.0과 호환되는지 추적하기 어렵다. Changesets는 변경 내역을 파일로 기록하고, 자동으로 버전을 범프하고 CHANGELOG를 생성한다.

이 글은 bluefoxdev.kr의 Changesets 패키지 관리 가이드 를 참고하여 작성했습니다.


1. Changesets 워크플로우

[Changesets 핵심 흐름]

1. 개발자가 PR에서 변경사항 기록:
   pnpm changeset
   → .changeset/random-name.md 파일 생성
   → 어떤 패키지가 어떻게 변경됐는지 기록 (patch/minor/major)

2. PR 머지 후 Changesets 봇이 "Version PR" 생성:
   → 모든 changeset 파일을 읽어 버전 범프
   → CHANGELOG.md 업데이트
   → package.json version 업데이트

3. Version PR 머지 시 자동 배포:
   → npm publish 실행
   → GitHub Release 생성

[버전 범프 규칙 (semver)]
  patch (1.0.X): 버그 수정, 내부 변경
  minor (1.X.0): 하위 호환 새 기능
  major (X.0.0): 호환성 깨지는 변경

[Linked Packages]
  @myapp/core 변경 시 @myapp/react도 같이 버전업
  → 사용자가 호환성 걱정 없이 설치 가능

2. Changesets 완전 설정

# 1. Changesets 설치
pnpm add -D @changesets/cli -w

# 2. 초기화
pnpm changeset init
# → .changeset/config.json 생성

# 3. 변경 기록 (개발자가 PR마다 실행)
pnpm changeset
# 대화형 CLI:
# - 변경된 패키지 선택
# - major/minor/patch 선택
# - 변경 내용 입력
// .changeset/config.json
{
  "$schema": "https://unpkg.com/@changesets/config@3.0.0/schema.json",
  "changelog": "@changesets/cli/changelog",
  "commit": false,
  "fixed": [],
  // ui와 react는 항상 같이 버전업
  "linked": [["@myapp/ui", "@myapp/react"]],
  "access": "public",
  "baseBranch": "main",
  "updateInternalDependencies": "patch",
  "ignore": ["@myapp/docs", "@myapp/examples"]  // 배포 제외 패키지
}
// .changeset/cobalt-dogs-dance.md (자동 생성)
---
"@myapp/ui": minor
"@myapp/core": patch
---

Button 컴포넌트에 `loading` props 추가

- `loading` prop으로 로딩 스피너 표시
- @myapp/core의 `useAsync` 훅 버그 수정 (#234)
# .github/workflows/release.yml
name: 릴리스

on:
  push:
    branches: [main]

concurrency: ${{ github.workflow }}-${{ github.ref }}

jobs:
  release:
    name: 릴리스
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
        with:
          fetch-depth: 0

      - uses: pnpm/action-setup@v4

      - uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'pnpm'
          registry-url: 'https://registry.npmjs.org'

      - run: pnpm install --frozen-lockfile

      - name: 빌드
        run: pnpm build

      - name: Changesets 봇 PR 생성 또는 배포
        uses: changesets/action@v1
        with:
          # PR이 없으면 생성, PR이 머지되면 배포
          version: pnpm changeset version
          publish: pnpm changeset publish
          title: '🚀 버전 업데이트'
          commit: '🔖 버전 업데이트'
        env:
          GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
          NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
          NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}
// packages/ui/package.json
{
  "name": "@myapp/ui",
  "version": "1.5.0",
  "description": "공유 UI 컴포넌트 라이브러리",
  "main": "./dist/index.js",
  "module": "./dist/index.mjs",
  "types": "./dist/index.d.ts",
  "exports": {
    ".": {
      "import": "./dist/index.mjs",
      "require": "./dist/index.js",
      "types": "./dist/index.d.ts"
    },
    "./button": {
      "import": "./dist/button.mjs",
      "require": "./dist/button.js"
    }
  },
  "files": ["dist"],
  "scripts": {
    "build": "tsup src/index.ts --format cjs,esm --dts",
    "dev": "tsup src/index.ts --format cjs,esm --dts --watch"
  },
  "peerDependencies": {
    "react": "^18.0.0 || ^19.0.0"
  },
  "devDependencies": {
    "@myapp/tsconfig": "workspace:*"
  }
}
// 사전 릴리스 (alpha/beta) 관리
// pnpm changeset pre enter alpha
// → .changeset/pre.json 생성
// → 이후 모든 버전은 1.6.0-alpha.0, 1.6.0-alpha.1, ...

// pnpm changeset pre exit
// → alpha 종료, 다음 버전은 정식 배포

// 특정 패키지만 배포 (emergency fix)
// pnpm changeset publish --filter @myapp/ui

// Turborepo와 통합
// turbo.json
// {
//   "pipeline": {
//     "build": {
//       "dependsOn": ["^build"],
//       "outputs": ["dist/**"]
//     },
//     "publish": {
//       "dependsOn": ["build"],
//       "cache": false
//     }
//   }
// }
// 버전 PR 예시 내용 (Changesets가 자동 생성)
// CHANGELOG.md
// ## 1.6.0 - 2026-04-23
//
// ### Minor Changes
// - Button 컴포넌트에 loading props 추가
//   (#234, @developer-name)
//
// ### Patch Changes
// - Updated dependencies:
//   - @myapp/core@2.3.1

// 내부 패키지 (배포 안 하는 것) 구분
// package.json에 "private": true 추가
// changeset config의 ignore 배열에 추가

마무리

Changesets는 변경 기록을 PR 시점에 개발자가 직접 작성하도록 강제한다. 이 파일이 쌓여 버전 PR이 생성될 때 CHANGELOG가 자동으로 만들어진다. linked 설정으로 관련 패키지의 버전을 동기화하면 사용자는 항상 호환되는 버전 조합을 사용할 수 있다. GitHub Actions와 결합하면 PR 머지 → 버전 PR 자동 생성 → 버전 PR 머지 → npm 배포까지 완전 자동화된다.