14. 설치와 구조
init에서 고르는 것 중 셋은 나중에 못 바꾼다
처음부터 끝까지
섹션 제목: “처음부터 끝까지”-
Next.js 프로젝트
Terminal window pnpm create next-app@latest my-appcd my-app -
shadcn/ui 초기화
Terminal window pnpm dlx shadcn@latest init -
첫 컴포넌트
Terminal window pnpm dlx shadcn@latest add button -
쓴다
app/page.tsx import { Button } from '@/components/ui/button'export default function Home() {return <Button>클릭</Button>}
전제 조건 두 가지: Tailwind가 설치돼 있을 것,
tsconfig.json에 @/* alias가 있을 것. create-next-app이 둘 다 해준다.
init이 하는 일
섹션 제목: “init이 하는 일”components.json생성 — 이후 모든 CLI 동작의 기준이 된다lib/utils.ts생성 —cn()함수 (11장)globals.css수정 — 토큰(:root,.dark)과@theme inline블록 추가- 의존성 설치 —
clsx,tailwind-merge,class-variance-authority, 프리미티브 - 아이콘 라이브러리 설치 — 기본은 lucide
3번이 12장에서 본 그 토큰 블록이다.
init 직후 globals.css를 열어보면 학습 효과가 크다.
components.json
섹션 제목: “components.json”{ "$schema": "https://ui.shadcn.com/schema.json", "style": "new-york", "rsc": true, "tsx": true, "tailwind": { "config": "", "css": "app/globals.css", "baseColor": "zinc", "cssVariables": true, "prefix": "" }, "aliases": { "components": "@/components", "ui": "@/components/ui", "utils": "@/lib/utils", "lib": "@/lib", "hooks": "@/hooks" }, "registries": {}}| 필드 | 의미 | 나중에 바꿀 수 있나 |
|---|---|---|
style |
컴포넌트의 시각적 성격 | 불가 |
rsc |
true면 필요한 파일에 use client 자동 추가 |
가능 |
tsx |
false면 .jsx로 생성 |
가능 |
tailwind.config |
v4에서는 빈 문자열 | — |
tailwind.css |
토큰을 주입할 CSS 파일 경로 | 가능 |
tailwind.baseColor |
중립색 계열 | 불가 |
tailwind.cssVariables |
true면 의미 토큰, false면 유틸리티 직접 | 불가 |
tailwind.prefix |
유틸리티 접두사 (tw- 등) |
가능 |
aliases.* |
파일이 놓일 위치 | 가능 |
registries |
외부 레지스트리 등록 | 가능 |
되돌릴 수 없는 세 가지
섹션 제목: “되돌릴 수 없는 세 가지”cssVariables를 반드시 true로
섹션 제목: “cssVariables를 반드시 true로”이 선택이 이 덱 전체에서 가장 중요한 설정 하나다.
<div className="bg-background text-foreground">- 다크 모드가 공짜 (12장)
- 테마 교체가 변수 몇 줄 (17장)
- 컴포넌트에 원시 색이 없다
<div className="bg-white text-zinc-950 dark:bg-zinc-950 dark:text-zinc-50">- 모든 컴포넌트에
dark:변형이 붙는다 - 테마 교체 = 전 파일 수정
- 17장의 작업이 사실상 불가능해진다
baseColor — 중립색 고르기
섹션 제목: “baseColor — 중립색 고르기”앱의 90%를 차지하는 회색 계열이다. 미묘하지만 인상 차이가 크다.
| 계열 | 성격 |
|---|---|
zinc |
완전 중립. 가장 무난하다 |
slate |
푸른 기. 차분하고 테크틱 |
stone |
따뜻한 기. 부드러움 |
neutral |
순수 무채색 |
mauve / olive / mist / taupe |
미세한 색조가 섞인 중립색 |
브랜드 색이 따뜻하면 stone/taupe, 차가우면 zinc/mist 쪽이 어울린다.
style — 여덟 가지 시각적 성격
섹션 제목: “style — 여덟 가지 시각적 성격”예전에는 default와 new-york 둘뿐이었다. 지금은 여덟 가지다.
| 스타일 | 성격 |
|---|---|
vega / nova |
예전 new-york 계열. 조밀하고 그림자 위주 |
maia / lyra / mira |
코어 라인업 |
luma |
2026년 3월 추가 |
rhea |
luma를 더 조밀하게. 밀도 높은 제품 화면용 |
sera |
타이포 중심. 세리프 제목 + 각진 모서리 + 밑줄 컨트롤 |
--style 플래그나 shadcn/create에서 고른다.
나중에 못 바꾸므로 프로젝트 시작 전에 웹사이트에서 실물을 비교해 보는 게 좋다.
flowchart TD
I["shadcn init"] --> A{"cssVariables"}
A -->|"true ✅"| OK["토큰 기반<br/>테마 교체 가능"]
A -->|"false ❌"| BAD["하드코딩 색<br/>17장 불가"]
I --> B["baseColor 선택<br/>zinc · slate · stone …"]
I --> C["style 선택<br/>8가지"]
B --> L["🔒 나중에 못 바꿈"]
C --> L
OK --> L2["🔒 나중에 못 바꿈"]
classDef ok fill:#dcfce7,stroke:#16a34a,color:#14532d
classDef bad fill:#fee2e2,stroke:#dc2626,color:#7f1d1d
classDef warn fill:#fef3c7,stroke:#d97706,color:#78350f
classDef mute fill:#f1f5f9,stroke:#94a3b8,color:#334155
class OK ok
class BAD bad
class L,L2 warn
class I,A,B,C mute
CLI 다루기
섹션 제목: “CLI 다루기”| 명령 | 하는 일 |
|---|---|
init / create |
프로젝트 설정 · 새 프로젝트 생성 |
add [name…] |
컴포넌트 추가 |
view [name…] |
설치 전에 소스를 미리 본다 |
search / list |
레지스트리에서 검색·목록 |
docs [name] |
컴포넌트 문서·API 조회 |
info |
현재 프로젝트 설정 확인 |
build |
registry.json → 배포용 JSON 생성 (16장) |
migrate |
아이콘 교체, RTL, radix 통합 패키지 전환 |
apply / preset |
프리셋(테마 등) 적용 (17장) |
eject |
shadcn 유틸을 인라인화하고 의존성 제거 (되돌릴 수 없음) |
알아두면 좋은 플래그
섹션 제목: “알아두면 좋은 플래그”# 설치 전에 소스 확인pnpm dlx shadcn@latest view button
# 무엇이 바뀔지만 보고 실행 안 함pnpm dlx shadcn@latest add dialog --dry-run
# 내가 수정한 파일과 최신 버전의 차이pnpm dlx shadcn@latest add button --diff
# 수정본을 덮어쓰기 (주의)pnpm dlx shadcn@latest add button --overwrite
# 전부 설치pnpm dlx shadcn@latest add --all
# 특정 경로에pnpm dlx shadcn@latest add card --path components/shared의존성이 자동으로 따라온다
섹션 제목: “의존성이 자동으로 따라온다”pnpm dlx shadcn@latest add dialog✔ Created 3 files: - components/ui/dialog.tsx - components/ui/button.tsx ← dialog가 필요로 해서 - hooks/use-media-query.ts ← 함께✔ Installed 1 package: - @base-ui-components/reactregistryDependencies가 다른 레지스트리 항목을 가리킨다dependencies는 npm 패키지를 가리킨다- 이미 있는 파일은 덮어쓰지 않는다 (
--overwrite없이는)
설치 후 파일 지도
섹션 제목: “설치 후 파일 지도”- components.json CLI의 기준. git에 커밋한다
디렉터리app/
- globals.css 토큰. 여기가 디자인 시스템의 뿌리
디렉터리lib/
- utils.ts
cn()
- utils.ts
디렉터리components/
디렉터리ui/ shadcn이 관리하는 영역
- button.tsx
- card.tsx
- dialog.tsx
이 네 가지가 앞으로 계속 나온다.
특히 globals.css와 components/ui/가 이 스택의 자산이 쌓이는 곳이다.
모노레포에서
섹션 제목: “모노레포에서”pnpm dlx shadcn@latest init --monorepo디렉터리apps/
디렉터리web/
- components.json →
"ui": "@workspace/ui/components"
- components.json →
디렉터리admin/
- components.json
디렉터리packages/
디렉터리ui/
- components.json 컴포넌트가 실제로 사는 곳
디렉터리src/components/
- …
- src/styles/globals.css 토큰도 여기
- 컴포넌트와 토큰은
packages/ui한 곳에만 둔다 - 각 앱은 그걸 import만 한다
add를 앱에서 실행해도 파일은packages/ui에 생긴다
14장 요약
섹션 제목: “14장 요약”init은 components.json · lib/utils.ts · globals.css 토큰 · 의존성을 만든다cssVariables: true는 반드시 켠다. 나중에 못 바꾸고, 테마 교체가 불가능해진다style과baseColor도 나중에 못 바꾼다 — 시작 전에 실물을 비교한다- 기본 베이스는 Base UI,
-b radix로 Radix 선택 가능 view(미리보기),--dry-run,--diff(수정 추적)를 기억한다- 모노레포는
packages/ui에 컴포넌트와 토큰을 모은다
15. 컴포넌트 해부button.tsx를 한 줄씩 — 소유한다는 것은 읽을 수 있다는 뜻이다.