29. 표준 라이브러리 스택 가이드
0. 먼저 알고 가기 (30초 요약)
- 같은 일을 하는 라이브러리는 저장소마다 다르지 않게 하나로 모읍니다.
-
HTTP는 ky, 서버 상태는 react-query, 클라이언트 상태는 zustand, URL 상태는 nuqs를
기본으로 둡니다.
- 버전은 pnpm catalog로 묶고, 의존 방향은 린트로 검사합니다.
초심자용 한눈에 보기
표준을 정해두면 저장소를 옮겨 다닐 때 매번 새로 익힐 필요가 줄고, 같은 문제를 같은
방법으로 풉니다. 도구를 줄이면 학습할 표면이 줄고, 보안 패치나 버전 업그레이드를 한
번에 적용하기 쉬워집니다.
핵심 용어 빠르게 정리
| 용어 |
쉬운 뜻 |
catalog |
워크스페이스 의존성 버전을 한 곳에 모아 고정하는 pnpm 기능 |
공유 인스턴스 |
인증·에러 처리를 미리 설정해 재사용하는 HTTP 객체 |
트리셰이킹 |
실제로 쓰는 코드만 번들에 남기는 최적화 |
의존 방향 |
app→domains→shared 순서로만 import를 허용하는 규칙 |
철회 조건 |
표준을 더 이상 유지하지 않고 바꾸기로 하는 명시적 기준 |
| 분류 |
핵심 기술 |
상태 |
Stable |
| 연관 가이드 |
04. 아키텍처,
05. API 통신
|
도구 원칙 |
벤더 중립 |
| 핵심 테마 |
HTTP·상태·URL·검증·로깅·스타일 표준, 선택 이유, 정렬 순서
|
Update |
최신 기준 |
"도구를 통일하는 목적은 멋이 아니라, 저장소를 옮겨도 같은 방식으로 읽고 고치고
지울 수 있게 하는 것이다."
이 문서는 카테고리마다 하나의 표준 라이브러리를 정하고, 왜 그것을 골랐는지와 어떻게
옮겨갈지를 함께 적습니다. 새 라이브러리가 더 분명한 이점을 보이면 철회 조건에 따라
교체합니다.
문서 책임 범위
0. 모든 프론트엔드 그룹 공통 Baseline
| 기준 |
최소 적용 |
| 한 카테고리 한 표준 |
같은 일을 하는 라이브러리는 저장소마다 다르지 않게 하나로 모읍니다.
|
| 공유 스키마 |
검증은 zod로 작성해 프론트와 백엔드가 함께 씁니다.
|
| 버전 정렬 |
공통 의존성은 catalog로 버전을 맞춥니다. |
| 구조 경계 |
import 방향은 린트로 검사합니다. |
| 점진 적용 |
큰 변경은 저장소별 작은 PR로 나눠 검증한 뒤 머지합니다.
|
0.1 교차 검증 매트릭스
| 권고 |
1차 출처 |
실행 증거 |
운영 증거 |
철회 조건 |
| 브라우저 HTTP는 ky 공유 인스턴스로 둔다 |
라이브러리 공식 문서 |
요청·에러·인증 헤더 테스트 |
API 에러율, 재시도율 |
플랫폼 fetch만으로 동일 요구가 더 단순할 때 |
| URL 상태는 nuqs로 둔다 |
라이브러리 공식 문서 |
딥링크·뒤로가기 E2E |
잘못된 파라미터 유입률 |
라우터 내장 기능으로 충분할 때 |
| NestJS 검증은 shared zod로 둔다 |
zod 문서, nestjs-zod 문서 |
DTO 검증 단위 테스트 |
잘못된 요청 4xx 비율 |
런타임 검증이 불필요한 내부 전용 경로일 때 |
| 의존 방향은 boundaries 린트로 강제한다 |
eslint-plugin-boundaries 문서 |
lint 위반 0건 |
구조 회귀 PR 수 |
단일 모듈 규모라 계층이 불필요할 때 |
0.2 운영 게이트
| Gate |
Evidence |
Owner |
Rollback |
| 라이브러리 채택 |
번들 diff, 라이선스 확인 |
플랫폼 오너 |
표준 외 라이브러리 제거 |
| 검증 계층 |
shared 스키마 테스트 |
백엔드 오너 |
이전 검증 방식 복원 |
| 구조 경계 |
boundaries lint 리포트 |
FE 오너 |
위반 import 되돌리기 |
| 버전 정렬 |
catalog diff |
플랫폼 오너 |
이전 버전 핀 복원 |
1. 표준 스택 카탈로그
1.1 프론트엔드 표준
| 영역 |
표준 |
한 줄 이유 |
| HTTP 클라이언트 |
ky |
ESM·경량·fetch 기반, 캐싱·재시도는 react-query 담당
|
| 서버 상태 |
@tanstack/react-query |
캐싱·재요청·동기화를 한 계층에 모음 |
| 클라이언트 상태 |
zustand |
작은 API, 보일러플레이트 최소 |
| URL/쿼리 파라미터 |
nuqs |
URL을 단일 상태원으로, 타입과 함께 다룸 |
| 폼 |
react-hook-form + @hookform/resolvers |
비제어 입력, 리렌더 최소 |
| 검증 |
zod |
프론트·백 공유 스키마 |
| 스타일 |
Tailwind CSS + clsx + tailwind-merge |
CSS-first·토큰화, 변형은 CVA |
| UI 프리미티브 |
Radix + lucide-react |
접근성 내장, 아이콘 일관 |
| 토스트 알림 |
sonner |
알림 스택·키보드·접근성 기본 제공 |
| 애니메이션 |
motion |
기존 라이브러리의 후속 패키지명 |
| 날짜 |
date-fns (+ date-fns-tz) |
트리셰이킹·함수형 |
| 유틸 |
es-toolkit |
작고 빠른 TS 우선 유틸 |
| 에러 경계 |
react-error-boundary |
Suspense·Error 경계 표준화 |
| 깊은 비교 |
dequal |
경량 deep compare |
| ID 생성 |
crypto.randomUUID() |
런타임 내장, 외부 의존 0 |
1.2 백엔드(NestJS) 표준
| 영역 |
표준 |
한 줄 이유 |
| DTO 검증 |
nestjs-zod |
shared zod 재사용, 이중 정의 제거 |
| 로깅 |
nestjs-pino |
구조적 JSON·요청 컨텍스트 |
| 인증 |
@nestjs/jwt + google-auth-library |
별도 추상화 계층 제거 |
| 비밀번호 해시 |
argon2 |
메모리-하드 해시 |
| ORM 기본값 |
Prisma (기존 Drizzle 저장소 유지) |
새 백엔드의 go-forward 기본값 |
1.3 툴체인 표준
| 영역 |
표준 |
한 줄 이유 |
| 패키지 매니저 |
pnpm + catalog |
워크스페이스 버전 단일화 |
| 빌드 |
Vite + Rolldown |
빠른 dev·번들 |
| React 컴파일 |
React Compiler (babel-plugin-react-compiler) |
자동 메모이제이션 |
| 린트 |
ESLint flat + eslint-plugin-react-compiler + eslint-plugin-boundaries
|
RC 규칙·계층 경계 강제 |
| 포맷 |
Prettier |
단일 포맷 |
| 테스트 |
vitest + @testing-library + msw + playwright |
Vite 변환 공유, e2e 분리 |
| 시크릿 스캔 |
secretlint |
pre-commit 유출 차단 |
| 타입 |
TypeScript strict |
null 안전 |
발행 공유 config 패키지 (@heejun/*)
위 툴체인 표준은 npm에 발행된 @heejun/* config 패키지로 구현되어, 각
저장소가 의존성으로 가져다 쓴다. 한 곳에서 관리하므로 설정 드리프트가 사라진다.
| 패키지 |
역할 |
@heejun/eslint-config |
ESLint flat config (typescript-eslint + React 19 + React Compiler + 계층 경계)
|
@heejun/prettier-config |
Prettier 설정 |
@heejun/typescript-config |
tsconfig (base / react / node) |
@heejun/tailwind-config |
Tailwind v4 CSS-first @theme |
@heejun/vite-config |
Vite 8 + React Compiler |
pnpm add -D @heejun/eslint-config @heejun/prettier-config @heejun/typescript-config @heejun/vite-config @heejun/tailwind-config
적용 방법
각 저장소는 인라인 설정을 지우고 위 패키지를 의존성으로 참조한다.
Prettier — package.json 에 설정 파일 대신 패키지명을
적고 인라인 .prettierrc 는 삭제한다. 기본값이 형제 저장소 공통
컨벤션(semi: false, trailingComma: 'es5')이라 재포맷 없이
채택된다. Tailwind 클래스 정렬이 필요하면 prettierConfigWithTailwind 를
쓴다.
// package.json
{ "prettier": "@heejun/prettier-config" }
ESLint — base() 와 react() 를 펼쳐 합친다.
base() 는 import 위생·typescript-eslint 권장 규칙·Prettier 충돌 비활성을
제공하고, react() 는 React 19·React Compiler·접근성 규칙을 더한다.
저장소별 정책(전역 함수 제한, 테스트 완화 등)은 뒤에 덧붙인다.
// eslint.config.mjs
import { base, react, defineConfig } from '@heejun/eslint-config'
export default defineConfig(
base({ files: ['**/*.{ts,tsx}'] }),
react({ files: ['apps/web/**/*.{ts,tsx}'] }),
// 저장소별 override는 뒤에 덧붙인다
)
테스트/목 컨벤션을 강제하는 heejunRules() 는 opt-in 이므로 필요한
저장소만 defineConfig(base(), react(), heejunRules()) 로 펼친다.
적용 시 알아둘 점 — eslint-plugin-jsx-a11y 는
minimatch v3을 쓰므로, 저장소가 minimatch v10을 전역
고정했다면 스코프 override(eslint-plugin-jsx-a11y>minimatch)로 v3을
함께 둔다. 의존성 감사 게이트가 있는 저장소는 eslint-plugin-boundaries 가
끌어오는 전이 의존성을 override로 고정한다.
2. 표준 선택 이유
-
ky (HTTP): ESM 네이티브이며 번들이 가볍고 플랫폼 fetch 위에서
동작합니다. 캐싱과 재시도는 react-query가 담당하므로, 클라이언트에는 얇은 fetch
래퍼만 있으면 충분합니다.
-
nuqs (URL/쿼리 파라미터): 화면 상태를 URL에 두면 뒤로가기,
새로고침, 링크 공유가 자연스럽게 동작합니다. 쿼리 파라미터를 타입과 함께 다뤄 수동
파싱 코드를 없앱니다.
-
sonner (토스트 알림): 알림 스택, 키보드 처리, 접근성 기본값을
제공해 별도 구현 부담을 줄입니다.
-
motion (애니메이션): 기존 라이브러리의 후속 패키지명으로 API가
이어지며, 앞으로의 릴리스 라인을 따릅니다.
-
date-fns / es-toolkit: 함수 단위로 임포트해 번들에 필요한 것만
포함됩니다. 타입 우선 설계라 별도 타입 패키지가 필요 없습니다.
-
argon2 (해시): 메모리 비용을 조절할 수 있는 해시로, 무차별 대입
공격에 더 강합니다.
-
nestjs-zod (검증): 프론트와 백엔드가 같은 zod 스키마를 공유해 검증
규칙이 한 곳에서 관리됩니다. 데코레이터 검증과의 이중 정의를 없앱니다.
-
nestjs-pino (로깅): 요청 컨텍스트가 붙은 구조적 JSON 로그로 관측성
도구와 바로 연동됩니다(09. 장애 대응).
-
ESLint flat + Prettier: React Compiler 규칙을 검사하는 플러그인이
ESLint 위에서만 제공되므로, 자동 메모이제이션의 안전망을 유지하려면 ESLint 계열을
유지합니다.
-
eslint-plugin-boundaries: app→domains→shared→infrastructure 의존
방향을 린트로 강제해 구조가 시간이 지나도 무너지지 않게 합니다(04. 아키텍처).
-
pnpm + catalog: 워크스페이스 전반의 버전을 한 곳에서 고정해
드리프트를 막습니다.
-
Prisma 기본값, 기존 Drizzle 유지: 새 백엔드는 Prisma를 기본으로
하되, 이미 Drizzle로 운영 중인 저장소는 옮기지 않습니다. 데이터 계층 이전은 위험
대비 효용이 낮습니다.
추천 항목 (실무 우선순위)
-
시작 추천: 버전 정렬과 패키지명 교체처럼 위험이 낮은 항목부터
맞춥니다.
-
안정 추천: HTTP·검증·토스트 알림 라이브러리를 표준으로 교체합니다.
-
운영 추천: 의존 방향 린트와 catalog로 다시 어긋나지 않게
고정합니다.
추천 항목 고도화 체크
-
즉시 적용 — 추천 항목 1개를 이번 주 내에 실제 작업 1건에 반영한다.
-
1주 내 정리 — 적용 결과를 PR 본문이나 회고 노트에 간단히 기록한다.
-
1개월 내 점검 — 재작업률/리뷰 충돌/배포 이슈 중 적어도 한 항목이
개선되었는지 확인한다.
추천 항목 실행 기록 템플릿
담당자 : 항목 적용 주체(문서 오너/팀원)를 명시
적용일 : 실제 반영된 날짜 및 작업 ID를 남김
측정 지표 : 리뷰 충돌/재작업/버그 재발 중 1개 이상 수치로 기록
-
보류 사유 : 적용을 못한 경우 이유를 1줄 기록하고 다음 액션을 지정
추천 항목 실행 우선순위 매핑
-
P1(7일 내) — 추천 항목 1개를 우선 적용하고 1회 사용자 관측
신호(에러율/실패율/지연)와 연결한다.
-
P2(30일 내) — 추천 항목 1개를 팀 내 표준/템플릿에 반영해 재사용성을
확보한다.
-
P3(90일 내) — 추천 항목 1개를 다른 관련 문서에 역링크로 연동해 중복
작업을 줄인다.
-
완료 기준 — 각 항목별 산출물(예: PR 링크/체크리스트/회고 노트)을 1개
이상 남긴다.
추천 항목 실행 체크리스트
- [ ]
1단계(7일) : 추천 항목 1개를 실제 작업으로 전환
-
[ ]
2단계(30일) : 전환 결과를 팀 산출물(ADR/PR/체크리스트)에 반영
- [ ]
3단계(60일) : 정적 지표 1개 이상으로 효과 검증
- [ ]
문제 대응 : 미달성 시 보류 사유와 다음 실행 액션을 문서화
추천 항목 실행 운영 규칙
-
실행 게이트 : 위험, 비용, 기대 효과가 1회 이상 정량화되어야 적용한다.
-
승인 체계 : 적용 전 사전 승인자(팀 리드/보안/운영)와 rollback 담당자를
확인한다.
-
리스크 점수 : 1~5 등급으로 현재 위험도를 기록하고 정량 기준을 남긴다.
-
리더 승인자 : 최종 승인 책임자(예: 팀 리드/PO/보안리더)를 명시한다.
승인 역할 : 승인자, 실행자, 모니터링 주체 역할을 분리해 적는다.
-
재개 조건 : 실패 신호가 기준치 이내로 돌아오면 다음 단계로 확장한다.
-
정지 조건 : 회귀 지표 악화가 1개 이상이면 즉시 중단하고 보류 사유를
갱신한다.
재평가 주기 : 최소 2주 단위로 상태를 리뷰하고 조정한다.
실무 적용 가이드
언제 이 문서를 펼칠까
- 새 저장소를 만들거나 라이브러리를 새로 추가할 때
- 같은 일을 하는 라이브러리가 저장소마다 달라 정리가 필요할 때
- 의존성 버전이 저장소 간에 어긋나 빌드나 동작이 갈릴 때
적용 순서
- 대상 저장소의 현재 라이브러리를 카테고리별로 정리한다.
- 이 문서의 표준과 다른 항목을 골라낸다.
- 저위험 항목(버전 정렬, 패키지명 교체)부터 작은 PR로 바꾼다.
- 라이브러리 교체(HTTP, 토스트 알림, 검증)는 동작 테스트와 함께 PR을 만든다.
- typecheck·lint·test·build를 모두 통과시킨 뒤 머지한다.
함께 두는 파일
- HTTP 공유 인스턴스:
src/infrastructure/http/
- env 스키마:
src/shared/config/
- 린트 경계 설정:
eslint.config.mjs
흔한 실수
- react-query를 쓰면서 HTTP 클라이언트에 재시도·캐싱을 또 얹어 동작이 중복된다.
- 버전을 저장소마다 손으로 올려 다시 어긋난다(catalog로 묶어야 한다).
- 검증 스키마를 프론트와 백엔드에 따로 정의해 규칙이 갈린다.
- 큰 구조 변경을 한 PR에 몰아 리뷰와 롤백이 어려워진다.
PR 완료 기준
- [ ] 변경한 카테고리가 이 문서의 표준과 일치한다
- [ ] typecheck·lint·test·build가 모두 통과한다
- [ ] 교체한 라이브러리의 동작을 테스트나 스모크로 확인했다
- [ ] 버전은 catalog 또는 공통 기준에 맞춰 정렬했다