Claude Code와 Nx Workspace로 시작하는 모노레포 가이드
Claude Code로 Nx Workspace 경계, nx graph, affected CI, 캐시를 구현하고 과한 모노레포를 피하는 입문서.
Nx Workspace는 큰 저장소가 아니라 경계를 보여주는 도구다
Claude Code에 “모노레포를 만들어줘”라고만 말하면 파일은 많이 생깁니다. 하지만 진짜 문제는 몇 주 뒤에 옵니다. apps/web 수정이 apps/admin을 깨뜨리는지, 버튼 컴포넌트가 앱 안에 있어야 하는지 공유 UI 라이브러리에 있어야 하는지, CI에서 매번 모든 테스트를 돌려야 하는지 헷갈리기 시작합니다.
Nx Workspace는 project graph, task graph, affected 명령, 캐시로 이 문제를 다룹니다. 공식 Nx mental model은 Nx가 프로젝트를 분석하고 필요한 작업만 실행하는 방식을 설명합니다. 입문자에게는 “의존 관계 지도와 작업 실행기”라고 이해하면 충분합니다.
이 글에서는 Claude Code를 무제한 생성기가 아니라 리뷰어이자 페어 프로그래머로 사용합니다. 공식 문서는 create-nx-workspace, workspace generators, affected, CI setup, caching tasks를 기준으로 봅니다. 함께 읽을 글은 Claude Code 모노레포 관리, pnpm workspace, CI/CD 설정입니다.
Nx를 쓸 만한 3가지 경우
Nx는 강력하지만 모든 작은 프로젝트에 필요하지는 않습니다. 랜딩 페이지 하나와 작은 API 하나라면 단순한 저장소가 더 빠를 수 있습니다. Nx는 경계와 검증 비용이 커질 때 가치가 생깁니다.
첫 번째 사용 사례는 여러 앱이 타입이나 UI를 공유하는 경우입니다. apps/web, apps/admin, apps/api, libs/contracts, libs/ui를 함께 두면 API 타입과 UI 기본 컴포넌트를 같은 PR에서 바꿀 수 있습니다.
두 번째는 선택적 CI입니다. 콘텐츠 사이트, 교육 페이지, 관리자 도구, API가 한 저장소에 있으면 모든 PR에서 전체 빌드를 돌리는 비용이 커집니다. nx affected -t test build는 Git 변경과 의존 그래프를 보고 영향을 받을 수 있는 프로젝트만 고릅니다.
세 번째는 Claude Code를 더 안전하게 쓰는 경우입니다. libs/ui는 화면 컴포넌트, libs/contracts는 API 타입, libs/config는 공통 도구 설정, apps/*는 배포 앱이라고 정하면 Claude Code의 제안 범위가 작아집니다. 광고, 제휴 링크, 상담 폼, 결제 CTA가 있는 페이지에서는 이 경계가 수익 보호 장치가 됩니다.
현재 경계를 설명하기 어렵다면 먼저 repo map first pass로 저장소 지도를 만드세요. Nx는 이미 설명 가능한 구조를 빠르게 만들 뿐, 혼란스러운 구조를 자동으로 정리하지 않습니다.
목표 구조
이 튜토리얼은 작은 workspace로 시작합니다. React 앱 2개, Node API 1개, UI 라이브러리, contracts 라이브러리, config 라이브러리입니다.
flowchart LR
web["apps/web\nReact + Vite"] --> ui["libs/ui\nUI primitives"]
admin["apps/admin\nReact + Vite"] --> ui
web --> contracts["libs/contracts\nAPI types"]
admin --> contracts
api["apps/api\nNode API"] --> contracts
web --> config["libs/config\nlint/test config"]
api --> config
규칙은 단순합니다. apps/*는 실행하고 배포하는 단위입니다. libs/*는 재사용하는 부품입니다. 라이브러리는 앱을 import하면 안 됩니다. UI 라이브러리는 API 환경 변수를 읽지 않고, contracts 라이브러리는 React 컴포넌트를 담지 않습니다.
작업 전 Claude Code에 경계를 먼저 줍니다.
이 Nx Workspace를 먼저 이해하고 아직 코드를 수정하지 마세요.
규칙:
- apps/web 과 apps/admin 은 프론트엔드 앱
- apps/api 는 API
- libs/ui 는 화면 표시용 UI 컴포넌트만 포함
- libs/contracts 는 API 타입과 Zod schema 포함
- libs/config 는 ESLint, Vitest, TypeScript 공통 설정 포함
- libs/* 는 apps/* 를 import하지 않음
수정 전 nx graph를 확인하고, 수정 후 검증용 nx affected 명령을 제시하세요.
그대로 실행할 수 있는 설정 명령
Node.js 20 이상, Git, pnpm이 있다고 가정합니다. 재현성을 위해 대화형 질문을 피합니다.
npx create-nx-workspace@latest acme-nx \
--workspaceType=integrated \
--preset=apps \
--packageManager=pnpm \
--nxCloud=skip \
--interactive=false
cd acme-nx
pnpm nx add @nx/react
pnpm nx add @nx/node
Nx generator로 앱과 라이브러리를 생성합니다. generator는 폴더뿐 아니라 Nx 설정, TypeScript path, 프로젝트 메타데이터까지 일관되게 갱신합니다.
pnpm nx g @nx/react:app web \
--directory=apps/web \
--bundler=vite \
--unitTestRunner=vitest \
--e2eTestRunner=playwright \
--style=css
pnpm nx g @nx/react:app admin \
--directory=apps/admin \
--bundler=vite \
--unitTestRunner=vitest \
--e2eTestRunner=none \
--style=css
pnpm nx g @nx/node:app api \
--directory=apps/api \
--unitTestRunner=vitest
pnpm nx g @nx/react:lib ui \
--directory=libs/ui \
--unitTestRunner=vitest
pnpm nx g @nx/js:lib contracts \
--directory=libs/contracts \
--unitTestRunner=vitest
pnpm nx g @nx/js:lib config \
--directory=libs/config \
--unitTestRunner=none
생성 후에는 먼저 그래프를 봅니다.
pnpm nx graph
pnpm nx show projects
pnpm nx show project web
그래프 선이 처음부터 복잡하다면 라이브러리를 더 만들기 전에 구조를 줄이세요.
project.json부터 읽기
입문자에게 project.json은 프로젝트에서 실행할 수 있는 작업 목록입니다.
{
"name": "web",
"sourceRoot": "apps/web/src",
"projectType": "application",
"targets": {
"build": {
"executor": "@nx/vite:build",
"outputs": ["{options.outputPath}"],
"options": {
"outputPath": "dist/apps/web"
}
},
"test": {
"executor": "@nx/vite:test",
"outputs": ["{workspaceRoot}/coverage/apps/web"],
"options": {
"passWithNoTests": true
}
},
"serve": {
"executor": "@nx/vite:dev-server",
"options": {
"buildTarget": "web:build"
}
}
},
"tags": ["scope:app", "type:web"]
}
Claude Code에는 먼저 설명을 요구합니다.
apps/web/project.json을 읽고 build, test, serve의 역할을 입문자에게 설명하세요.
변경이 필요하면 가장 작은 diff만 제안하세요.
outputs, cache 동작, dependsOn 관계를 깨뜨리지 마세요.
outputs는 Nx 캐시에 사용됩니다. 경로가 틀리면 캐시가 무효가 되거나 오래된 산출물이 재사용될 수 있습니다.
affected를 CI에 넣기
affected는 Nx의 실무 가치가 가장 잘 보이는 기능입니다. Git 변경과 프로젝트 그래프를 비교해 영향을 받을 수 있는 프로젝트에만 작업을 실행합니다.
pnpm nx affected -t lint test build --base=main --head=HEAD
pnpm nx affected:graph --base=main --head=HEAD
GitHub Actions에서는 브랜치 비교를 위해 전체 히스토리를 가져옵니다. 또한 vitest, eslint, tsc를 직접 부르지 말고 nx를 통해 실행해야 캐시와 affected가 동작합니다.
name: nx-ci
on:
pull_request:
push:
branches: [main]
jobs:
affected:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- uses: pnpm/action-setup@v4
with:
version: 10
- uses: actions/setup-node@v4
with:
node-version: 20
cache: pnpm
- run: pnpm install --frozen-lockfile
- run: pnpm nx affected -t lint test build --base=origin/main --head=HEAD --parallel=3
팀에서는 Nx Cloud 원격 캐시도 고려할 수 있습니다. 처음에는 로컬 캐시와 affected로 효과를 확인한 뒤 CI 시간이 병목이 될 때 도입하는 편이 좋습니다.
흔한 실패
첫째, libs/shared를 만들고 모든 것을 넣는 것입니다. 이동 전에 Claude Code에 UI, contracts, config, 순수 유틸 중 어디에 속하는지 설명하게 하세요.
둘째, libs/*에서 apps/*를 import하는 것입니다. 의존 방향이 뒤집히면 라이브러리를 재사용하기 어렵습니다.
셋째, CI에서 원본 도구를 직접 실행하는 것입니다. pnpm nx run-many -t test 또는 pnpm nx affected -t test를 우선 사용하세요.
넷째, 첫 주부터 과하게 설계하는 것입니다. 실제 중복이 생기기 전에는 libs/auth, libs/domain, libs/data-access를 늘리지 마세요.
다섯째, Claude Code에 graph 없이 수정하게 하는 것입니다. 작업 전 pnpm nx graph, 작업 후 pnpm nx affected -t test build를 프롬프트에 넣으세요.
수익화 관점: 돈이 되는 페이지 보호하기
ClaudeCodeLab 같은 사이트에서는 글, 교육 페이지, 관리자 도구, 리드 폼, analytics가 한 저장소에 있을 수 있습니다. Nx의 가치는 속도뿐 아니라 수익 관련 페이지가 영향을 받았는지 설명할 수 있다는 점입니다. libs/cta가 바뀌면 어떤 페이지를 확인해야 하는지 graph로 볼 수 있고, libs/analytics가 바뀌면 affected CI로 어떤 앱에 스모크 테스트가 필요한지 알 수 있습니다.
이는 AdSense 레이아웃, 제휴 블록, 결제 CTA, 상담 폼에 특히 중요합니다. 팀에서 Claude Code와 모노레포 운영을 표준화하려면 ClaudeCodeLab training을 참고하세요. 혼자 실험한다면 이 글의 명령을 실행하고 nx graph 스크린샷을 남기는 것부터 시작하면 됩니다.
직접 검증한 결과
Masa로 검증할 때 처음에는 web, admin, api, ui, contracts만 만들었습니다. libs/contracts의 타입을 바꾼 뒤 pnpm nx affected -t test build --base=main --head=HEAD를 실행하니 contracts에 의존하는 앱만 선택되었습니다. libs/ui만 바꿨을 때는 API build가 범위에서 제외되었습니다. 중요한 교훈은 Nx 옵션 암기가 아니라, graph와 경계를 먼저 보이게 하면 Claude Code의 변경이 작고 리뷰 가능해진다는 점입니다.
정리
Nx Workspace는 저장소를 크게 만들기 위한 도구가 아닙니다. 의존 관계를 보이게 하고, 영향을 받은 프로젝트만 검증하고, Claude Code가 지킬 경계를 주는 도구입니다.
작게 시작하고, project.json을 읽고, nx graph를 확인하고, nx affected를 CI에 넣으세요. 그러면 Claude Code는 파일 생성기가 아니라 모노레포 구조를 지키는 리뷰어가 됩니다.
무료 PDF: Claude Code 치트시트
이메일을 입력하면 명령, 리뷰 습관, 안전한 워크플로를 정리한 PDF를 받을 수 있습니다.
개인정보를 안전하게 관리하며 스팸을 보내지 않습니다.
작성자 소개
Masa
Claude Code 실무 워크플로와 팀 도입을 검증하는 엔지니어입니다.
관련 글
Claude Code 무료 PDF 퍼널 체크리스트: 글 유입을 등록과 상품 클릭으로 바꾸기
글 독자를 무료 PDF, Gumroad 상품, 상담으로 연결하는 Claude Code 점검표입니다.
Obsidian 메모를 CLAUDE.md로 바꾸는 Claude Code 워크플로
Obsidian 작업 메모를 CLAUDE.md 운영 노트로 정리해 Claude Code 세션의 문맥 반복을 줄입니다.
Claude Code Revenue CTA Routing: 글에서 PDF, Gumroad, 상담으로 보내기
독자 의도에 따라 무료 PDF, Gumroad 상품, 상담으로 나누는 Claude Code CTA 설계입니다.