궁합이 맞는 지점
shadcn/ui는 Tailwind로 스타일링되어 있다.
Tailwind는 빌드 타임에 클래스를 스캔하니 Next.js 파이프라인에 그대로 얹힌다.
shadcn 컴포넌트는 RSC를 전제로 만들어져 use client가 필요한 것에만 붙어 있다.
셋은 경쟁하지 않는다. 완전히 다른 층에 있다
초심자가 가장 많이 하는 오해가 “Next.js vs Tailwind vs shadcn 중에 뭘 골라야 하나”다. 셋은 고르는 대상이 아니라 쌓는 층이다.
flowchart TB
A["shadcn/ui — 컴포넌트<br/>버튼 · 다이얼로그 · 폼이 어떻게 생기고 동작하는가"]
B["Tailwind CSS — 스타일 언어<br/>그 생김새를 어떤 문법으로 기술하는가"]
C["Next.js — 실행 환경<br/>그 컴포넌트를 언제 · 어디서 실행하는가"]
D["React — UI 모델<br/>상태가 바뀌면 화면이 바뀐다"]
A --> B --> C --> D
classDef warn fill:#fef3c7,stroke:#d97706,color:#78350f
classDef ok fill:#dcfce7,stroke:#16a34a,color:#14532d
classDef key fill:#dbeafe,stroke:#2563eb,color:#1e3a8a
classDef mute fill:#f1f5f9,stroke:#94a3b8,color:#334155
class A warn
class B ok
class C key
class D mute
각 층은 아래 층을 전제하지 대체하지 않는다. 한 문장씩 하면 —
세 도구는 전부 실제로 아팠던 문제에서 나왔다. 그 통증을 모르면 왜 이렇게 생겼는지 이해가 안 된다.
sequenceDiagram
participant B as 브라우저
participant C as CDN
participant A as API 서버
B->>C: index.html 요청
C-->>B: 거의 빈 HTML + 1.2MB JS
Note over B: 흰 화면. JS 다운로드·파싱 대기
B->>A: /api/user
A-->>B: JSON
B->>A: /api/posts (user 를 받은 뒤에야 가능)
A-->>B: JSON
Note over B: 이제서야 첫 화면
/* 이 클래스 이름을 뭐라고 지을 것인가로 30분 */.card { }.card__header { }.card__header--highlighted { }.card__header--highlighted-compact { } /* 여기서부터 무너진다 */.title이 내 .title을 덮어쓴다전통적인 컴포넌트 라이브러리(MUI, Ant Design, Chakra)는 node_modules에 들어온다.
sx, theme.overrides, !important)근본 원인은 하나다 — 내가 쓰는 코드를 내가 소유하지 않았다.
셋은 같은 사람들이 같은 시기에 만든 게 아닌데도 유독 잘 맞는다.
궁합이 맞는 지점
shadcn/ui는 Tailwind로 스타일링되어 있다.
Tailwind는 빌드 타임에 클래스를 스캔하니 Next.js 파이프라인에 그대로 얹힌다.
shadcn 컴포넌트는 RSC를 전제로 만들어져 use client가 필요한 것에만 붙어 있다.
결과
shadcn add button 한 줄이면 끝.
디자인 변경 = 내 레포의 파일 수정.
토큰 하나 바꾸면 앱 전체가 따라 바뀐다.
공통점은 **“추상화를 얇게 유지한다”**는 태도다. 어느 쪽도 아래 층을 가리지 않기 때문에 겹쳐 써도 서로 부딪히지 않는다.
정직하게 짚고 간다. 아래에 해당하면 다른 선택이 낫다.
반대로 제품을 오래 만들 예정이고 디자인이 계속 바뀔 것이라면 이 조합의 이점이 가장 크게 나타난다.
| 층 | 이 덱의 선택 | 주요 대안 | 언제 대안이 낫나 |
|---|---|---|---|
| 메타 프레임워크 | Next.js | Remix/React Router, TanStack Start, Astro | 서버 중심 폼 / 콘텐츠 사이트 |
| 스타일 | Tailwind | CSS Modules, Panda CSS, vanilla-extract | 런타임 zero + 타입 안전 CSS가 최우선 |
| 컴포넌트 | shadcn/ui | MUI, Ant Design, Mantine, Chakra | 완성된 복합 위젯이 당장 필요 |
| 프리미티브 | Base UI | Radix, React Aria, Headless UI | 이미 쓰고 있는 것이 있음 |
Panda CSS와 vanilla-extract는 Tailwind와 철학이 비슷하지만 타입 안전성을 더 중시한다. 빌드 복잡도가 올라가는 대신 CSS 값에 타입이 붙는다.
덱 전체를 관통하는 질문을 여기서 한 번 더 심어둔다.
Tailwind의 클래스 스캔, generateStaticParams, 정적 껍데기 생성.
특징 — 사용자 요청과 무관하게 미리 끝난다. 그래서 동적인 값을 알 수 없다.
Tailwind가 `text-${color}-500` 을 못 찾는 이유가 정확히 이것이다. (10장)
서버 컴포넌트의 DB 쿼리, cookies(), Server Function 실행.
특징 — 요청마다 다르지만 브라우저로는 코드가 안 간다. 비밀 키를 써도 되고, 번들 크기에 영향을 주지 않는다. (2·5·6장)
useState로 열리는 드롭다운, onClick, localStorage, 애니메이션.
특징 — 인터랙션이 가능한 대신 모든 코드가 다운로드된다. 경계를 잘못 그으면 여기로 오는 양이 폭발한다. (4장)