07 — When NOT to Use GraphQL
한 줄 답: GraphQL은 만능 도구가 아니다. (a) 단순 CRUD, (b) 큰 파일 streaming, (c) 강한 HTTP 캐시 의존, (d) 팀이 GraphQL 운영 경험 0, (e) 클라이언트가 모두 자기 팀이고 1:1 BFF로 충분한 경우 — 이 중 하나라도 강하게 해당하면 REST or RPC가 더 낫다. 도입 비용은 학습·운영·관측·보안 네 갈래로 모두 든다.
Why — 왜 이 문서가 필요한가
GraphQL 도입 회의에서 가장 자주 빠지는 것이 “안 쓰는 게 나은 경우”의 검토다. GraphQL 진영의 책·블로그·컨퍼런스 자료는 대부분 도입의 장점만 다룬다. 그래서 6개월~1년 운영해 본 팀들 사이에서 *“우리 케이스에 GraphQL이 안 맞았다”*는 회고가 자주 나온다 — Coinbase, Wayfair, Medium 등의 공개 회고가 이 갈래에 속한다.
이 문서는 그 회고들을 5가지 패턴으로 정리한다. 도입 전에 한 번 검토하고, 해당하면 GraphQL을 피하는 것이 더 나은 선택임을 인정하는 것이 목적.
How — 5가지 부적합 패턴
패턴 (a) — 단순 CRUD
가장 흔한 부적합 케이스.
GET /users/:id
POST /users
PUT /users/:id
DELETE /users/:id이 모양이 그 자체로 모델이라면, GraphQL을 얹는 것은 overhead만 추가다.
| 비교 | REST | GraphQL |
|---|---|---|
| 한 화면 → 한 호출 | YES | YES |
| 응답 모양 변동 | NO (고정 User) | YES (그러나 필요 없음) |
| 관계 traversal | NO (필요 없음) | YES (그러나 필요 없음) |
| codegen | OpenAPI 한 줄 | schema + tooling + Apollo |
| 학습 곡선 | 누구나 | learning curve 있음 |
| 캐시 | HTTP cache OK | 어려움 |
→ 결론: 화면이 고정 모양 단일 리소스만 다루면 REST가 압도적으로 단순하다.
판단 기준:
- 클라이언트가 한 종류이고
- 화면이 리소스 1대1 매핑 (예: 상품 상세, 사용자 프로필)
- 관계 traversal이 거의 없음
→ 이 셋이 다 맞으면 REST.
패턴 (b) — 큰 파일 streaming
시도: { uploadVideo(file: "...base64...") { url } }
↑ 50MB → JSON 안에 base64로 → 약 67MBGraphQL은 JSON 본문이라 binary에 약하다. multipart spec(graphql-multipart-request-spec)이 있지만 복잡하고 모든 클라이언트가 지원하지 않는다.
| 시나리오 | 적합 |
|---|---|
| 영상 업로드/다운로드 | REST (multipart, range request) |
| 큰 이미지 처리 | REST + CDN |
| WebRTC streaming | WebRTC (별도) |
| 실시간 binary feed | gRPC bidirectional or WebSocket |
| 메타데이터만 | GraphQL OK (binary는 URL 반환) |
→ 결론: binary는 별도 endpoint. GraphQL은 그 URL의 metadata만 다룸.
실패 사례:
- 한 이커머스 회사가 상품 이미지를 GraphQL
uploadImagemutation으로 받았다가, 대용량 트래픽에서 메모리 폭발. 6개월 뒤 S3 presigned URL + REST로 전환.
패턴 (c) — 강한 HTTP 캐시 필요
GET /products/123
Cache-Control: public, max-age=300
ETag: "abc"REST의 가장 큰 무기 — CDN과 브라우저 캐시가 그대로 동작.
GraphQL은:
- POST가 default → 브라우저 캐시 안 됨
- body가 매번 다름 → CDN 캐시 어려움
- 응답이 매번 다른 모양 → normalize 캐시 필요 (Apollo Client cache)
| 캐시 종류 | REST | GraphQL |
|---|---|---|
| 브라우저 HTTP cache | 자동 | 없음 |
| CDN edge cache | 자동 | persisted query + GET 필요 |
| reverse proxy cache | 자동 | 어려움 |
| 응용 레벨 cache | 별도 | normalized cache (Apollo·urql) |
→ persisted query + GET으로 GraphQL을 CDN cacheable하게 만들 수 있긴 하지만 추가 복잡도. 이 모든 게 공짜로 오는 REST와 비교하면 명백히 불리하다.
판단 기준:
- 응답이 대부분 정적 (상품 카탈로그, 공개 콘텐츠)
- 트래픽이 매우 큼 (CDN이 critical)
- 동일 응답을 수만 명에게 전달
→ 이 셋이 맞으면 REST.
패턴 (d) — 팀이 GraphQL 운영 경험 0
이게 가장 자주 무시되는 패턴이다.
GraphQL을 처음 production에 올리는 팀이 만나는 함정들:
각 함정은 production 사고로 직결된다. REST는 함정이 더 적다 — 산업이 20년의 운영 노하우를 축적한 도구.
판단 기준:
- 팀에 GraphQL을 production에 운영해 본 사람이 없고
- 코칭/멘토링 받을 외부 자원도 없고
- 학습 6개월을 감내할 수 없는 일정
→ 이 셋이 맞으면 REST.
패턴 (e) — 클라이언트가 모두 자기 팀, 1:1 BFF 가능
GraphQL의 가치 제안은 N 클라이언트가 N 모양을 원할 때 극대화된다. 만약:
- 클라이언트가 하나뿐 (예: 웹 + 모바일이 거의 같은 모양)
- 클라이언트 팀과 백엔드 팀이 같음 — 즉시 협의 가능
- 전통 BFF (REST) 한 개로 충분히 적응
→ GraphQL의 유연성이 과한 비용이 된다.
TS 모노레포 풀스택이라면 → tRPC가 더 가벼움 (04 참고)
비-TS 풀스택이라면 → REST가 가장 단순.
What — 실제 회고 사례
Coinbase의 회고 (2020)
- 도입: 2016년 GraphQL 적극 도입
- 회고: “public API에는 REST를 유지했다”
- 이유: 외부 개발자가 REST에 익숙했고, GraphQL learning curve가 적용률을 떨어뜨림
- 결론: 외부 API는 REST, 내부 BFF는 GraphQL
Wayfair의 회고
- 도입: 마이크로서비스 통합용 GraphQL Federation
- 회고: 일부 시나리오에서 오버스펙
- 결론: 단순 service-to-service는 gRPC가 더 적합. Federation은 클라이언트 통합 layer에만.
Medium의 회고
- 도입: 2018년 GraphQL 적용
- 회고: 팀의 GraphQL 운영 경험 부족으로 N+1, 복잡도 폭주
- 결론: DataLoader · persisted query · field auth가 처음부터 필요했음. 운영 경험이 없는 팀이라면 REST가 안전.
Netflix Falcor → GraphQL
- Falcor를 만들고 4년 사용 → GraphQL로 전환
- 이유: *생태계 (codegen·tooling·교육 자료)*가 GraphQL이 압도적
- 교훈: 기술적 우수성과 생태계 채택은 다르다. 맞는 도구를 골랐어도 생태계가 약하면 진다.
한국 — 우아한형제들
- 배민 광고 시스템에 GraphQL 도입
- 회고: 광고 도메인의 가변 모양에 잘 맞았음. 결제 도메인에는 REST를 유지. 도메인별 적합도 분리.
What-if — 부적합 패턴인데도 GraphQL을 강행하면
1) 단순 CRUD인데 GraphQL 도입
→ 학습 곡선에 1~3개월. codegen 파이프라인 운영 부담. 팀의 시간이 비즈니스가 아닌 도구 운영으로 빠짐. 대응: REST + OpenAPI로 시작, 화면이 진짜로 가변해질 때 GraphQL 추가.
2) 큰 파일을 GraphQL로 받음
→ JSON base64로 부피 30~50% 증가. multipart spec 복잡. 대용량 트래픽에서 메모리 폭발. 대응: binary는 항상 별도 endpoint. GraphQL은 metadata만.
3) HTTP 캐시 의존인데 GraphQL
→ CDN 캐시 무용. 트래픽 비용 폭증. 응답 지연 증가. 대응: persisted query + GET을 처음부터 도입. 또는 그 영역은 REST로 유지.
4) GraphQL 경험 없는 팀에 도입
→ N+1로 DB 폭주. depth 제한 없는 쿼리로 DoS 취약. field-level 인가 누락으로 데이터 노출. 대응: 외부 컨설팅 or 안 함. 보안 사고 한 번이 도입 비용보다 크다.
5) 1:1 BFF로 충분한데 GraphQL
→ overhead만 큼. 클라이언트가 더 빨라지지도 않음. 대응: 진짜로 N개 클라이언트가 생길 때까지 REST.
Insight — 흥미로운 이야기
”Hype Curve의 함정”
Gartner Hype Cycle은 모든 기술이 Peak of Inflated Expectations → Trough of Disillusionment를 거친다고 말한다. GraphQL은 2015~2019년에 최고점을 찍었다. 2020년 이후 환멸의 골짜기를 지나 생산성의 고원에 자리 잡는 중이다.
환멸의 골짜기에서 나온 회고들이 이 챕터의 자료다 — 적합한 자리·부적합한 자리가 산업 합의로 정리된 시점. 2026년 시점에서 GraphQL을 도입한다면 그 합의를 무시하지 않는 것이 옳다.
”Apollo의 마케팅 전환”
Apollo는 2018년경 *“Replace REST with GraphQL”*을 강하게 밀었지만, 2023년 이후 공식 자료는 *“GraphQL은 graph layer, REST는 resource layer — 함께 살 수 있다”*로 톤이 바뀌었다. 시장이 가르친 교훈을 가장 큰 GraphQL 회사가 인정한 것.
”GitHub의 5년”
GitHub는 2017년 GraphQL v4를 공개하며 “REST 대체”를 목표로 했다. 5년 뒤 (2022), 그들의 공식 입장은 “REST와 GraphQL은 상호 보완이다”. 일부 기능(repository graph traversal)은 GraphQL이 압도적으로 낫고, 다른 기능(file content, raw blob)은 REST가 압도적으로 낫다. 한 회사의 모든 API를 한 도구로 통일하지 못한다는 결론.
”한국의 도입 패턴”
한국 IT 회사들은 2018~2022년에 GraphQL을 적극 검토했고, 2023년 이후 선별 도입으로 정리됐다. 카카오·네이버·우아한형제들 등은 광고·콘텐츠 피드 같은 가변 영역에 GraphQL을 쓰고, 결제·로그인·정산은 REST/gRPC 유지. 도메인별 적합도 분리가 국내 합의에 가깝다.
요약 + 다이어그램
GraphQL은 만능이 아니다. 단순 CRUD · 큰 파일 · 강한 HTTP 캐시 · 운영 경험 0 · 1:1 BFF — 이 중 하나라도 강하게 해당하면 REST/RPC가 더 낫다. 도입 결정은 기능 매력이 아니라 5가지 안티-패턴 체크를 통과한 뒤 내려야 한다.
다음 챕터:
09-real-world-cases— 이 매트릭스를 실제 회사들은 어떻게 적용했나?