REST와 GraphQL의 가장 근본적인 차이는 데이터 형태를 누가 결정하느냐다.
- REST: 서버가 결정한다.
GET /users/1은 서버가 미리 정의한 User 객체를 반환한다. 클라이언트는 그 형태 전체를 받는다. - GraphQL: 클라이언트가 결정한다. 클라이언트가 쿼리에 필요한 필드를 명시하면 서버는 그 필드만 반환한다.
이 차이에서 모든 장단점이 파생된다.
한 줄 요약: GraphQL은 클라이언트가 필요한 데이터를 정확히 요청하는 구조고, REST는 서버가 정의한 엔드포인트에서 데이터를 가져온다. 2026년 기준으로 두 기술은 공존하며, 선택 기준은 팀 구성, 프로덕트 특성, 운영 역량에 달려 있다. REST와 GraphQL의 가장 근본적인 차이는 데이터 형태를 누가 결정하느냐다. REST: 서버가 결정한다.
한 줄 요약: GraphQL은 클라이언트가 필요한 데이터를 정확히 요청하는 구조고, REST는 서버가 정의한 엔드포인트에서 데이터를 가져온다. 2026년 기준으로 두 기술은 공존하며, 선택 기준은 팀 구성, 프로덕트 특성, 운영 역량에 달려 있다.
GraphQL이 나온 지 10년이 넘었지만 REST를 완전히 대체하지 못했다. 이유가 있다. GraphQL이 해결하는 문제가 분명하지만, 그 해결이 새로운 복잡성을 만든다. 이 글은 쿼리 유연성, 오버/언더페칭, 캐싱, 타입 시스템, 도구 생태계를 기준으로 두 접근 방식을 비교하고, 어떤 상황에서 무엇을 선택해야 하는지 판단 기준을 제시한다.
REST와 GraphQL의 가장 근본적인 차이는 데이터 형태를 누가 결정하느냐다.
GET /users/1은 서버가 미리 정의한 User 객체를 반환한다. 클라이언트는 그 형태 전체를 받는다.이 차이에서 모든 장단점이 파생된다.

오버페칭(Overfetching)은 필요한 것보다 많은 데이터를 받는 것이다. 모바일 앱에서 사용자 이름만 표시하면 되는데 REST 엔드포인트가 프로필 이미지, 주소, 결제 정보까지 반환하는 경우다. 불필요한 데이터가 네트워크 대역폭을 낭비하고, 특히 저사양 모바일 환경에서 체감된다.
언더페칭(Underfetching)은 하나의 뷰를 렌더링하기 위해 여러 엔드포인트를 호출해야 하는 것이다. 게시글 목록과 각 게시글 작성자 정보를 함께 보여주려면 GET /posts 후 각 GET /users/{id}를 반복 호출해야 하는 N+1 문제가 대표적이다.
GraphQL은 이 두 문제를 동시에 해결한다. 단 하나의 쿼리로 게시글과 작성자 이름을 정확히 요청할 수 있다.

REST — 게시글 목록 + 작성자 이름 조회 (N+1 문제)// 1단계: 게시글 목록 조회 GET /api/posts // Response: [{ id: 1, title: '...', authorId: 42 }, ...] // 2단계: 각 게시글의 작성자 조회 (N번 호출) GET /api/users/42 // Response: { id: 42, name: 'Alice', email: '...', address: '...' } // → name만 필요하지만 전체 User 객체를 받음 (오버페칭) // 총 호출 수: 게시글 수 + 1
GraphQL — 단일 쿼리로 필요한 데이터만 조회# 단 한 번의 요청으로 필요한 데이터만 지정 query GetPostsWithAuthors { posts { id title author { name # email, address 등은 요청하지 않음 } } } # Response: # { # "data": { # "posts": [ # { "id": 1, "title": "...", "author": { "name": "Alice" } } # ] # } # } # 총 호출 수: 1
캐싱은 REST가 GraphQL보다 구조적으로 유리한 영역이다.
REST는 HTTP 캐싱을 그대로 활용한다. GET /posts/1은 URL이 고정되어 있어 CDN이나 브라우저가 응답을 캐싱할 수 있다. Cache-Control, ETag, Last-Modified 헤더가 표준 HTTP 캐싱 메커니즘과 자연스럽게 통합된다.
대부분의 GraphQL 구현은 HTTP POST를 사용한다. POST 요청은 HTTP 표준상 기본 캐싱 대상이 아니다. 따라서 URL 기반 CDN 캐싱이 동작하지 않는다.
GraphQL은 대신 Persisted Queries(쿼리를 해시로 등록하고 GET으로 요청), Apollo Client 캐시(클라이언트 사이드 캐싱), DataLoader(배치 처리와 메모이제이션)로 캐싱 문제를 보완한다. 하지만 이 모든 것은 별도로 설정해야 한다.
외부 개발자가 사용하는 공개 API라면 REST가 여전히 표준이다. HTTP 캐싱, 다양한 클라이언트 지원, 브라우저에서 직접 테스트 가능한 단순함이 장점이다. GitHub, Twitter/X, Stripe 등 대부분의 공개 API는 REST를 기본으로 쓴다(일부는 GraphQL을 추가로 제공).
GraphQL의 가장 큰 장점 중 하나는 스키마가 API의 단일 진실 소스가 된다는 것이다. 스키마에서 타입, 관계, 입력/출력 형식이 모두 정의되며, 이를 기반으로 타입스크립트 타입, 문서, 클라이언트 SDK를 자동 생성할 수 있다.
REST 자체에는 타입 시스템이 없다. 하지만 OpenAPI(Swagger)로 스키마를 정의하면 유사한 수준의 타입 생성, 문서화, 모킹이 가능하다. tRPC는 별도 스키마 없이 TypeScript 타입만으로 REST와 유사한 엔드포인트를 타입 안전하게 만든다.
GraphQL 서버에서는 리졸버가 중첩 타입을 처리하다 보면 N+1 쿼리가 발생하기 쉽다. DataLoader 패턴으로 배치 처리하면 해결된다. 단, DataLoader 설정은 개발자가 직접 해야 하며, 이 부분이 GraphQL 도입의 초기 학습 비용을 높인다.

가장 빈번한 함정은 리졸버에서 발생하는 N+1 쿼리를 방치하는 것입니다. 게시글 목록을 받고 각 게시글의 작성자를 중첩 필드로 요청하면 작성자 수만큼 DB 쿼리가 따로 나가는데, DataLoader 패턴으로 배치 처리하지 않으면 트래픽이 늘수록 DB가 먼저 무너집니다. 두 번째는 보안 설정 누락입니다. GraphQL은 클라이언트가 쿼리 형태를 자유롭게 짜기 때문에 Depth Limit, Complexity Limit, Rate Limiting을 걸지 않으면 깊게 중첩된 악성 쿼리 한 방으로 서버가 다운될 수 있습니다. 마지막으로 POST 기반이라 HTTP 캐싱이 자동으로 동작하지 않는다는 점을 간과하고 REST처럼 CDN 캐싱을 기대하는 경우가 많습니다.
GraphQL은 여러 종류의 클라이언트가 같은 백엔드에서 서로 다른 데이터 형태를 요구하거나, 모바일처럼 오버페칭이 체감되는 환경, 소셜 그래프·커머스 카탈로그처럼 중첩 관계를 단일 쿼리로 가져와야 하는 SPA에 적합합니다. 실시간 알림이 필요하면 Subscription이 내장된 점도 강점입니다. 반대로 외부 개발자에게 공개하는 API라면 HTTP 캐싱과 폭넓은 클라이언트 지원을 갖춘 REST가 여전히 사실상 표준이라 더 낫고, 팀이 작아 DataLoader·Depth Limit 설정 같은 학습 비용을 감당하기 어렵거나, 고정된 클라이언트 하나에 단순 CRUD와 파일 업로드만 필요한 경우에는 GraphQL이 과합니다. 마이크로서비스 내부 통신이라면 gRPC가 더 맞을 수도 있습니다.
기초는 GraphQL 공식 학습 문서(graphql.org/learn)로 스키마·쿼리·리졸버 개념을 잡으시고, 실제 서버·클라이언트 구현은 Apollo 공식 문서(apollographql.com/docs)가 가장 체계적입니다. 여기서 한 단계 더 들어간다면 꼭 익혀야 할 핵심 개념은 세 가지입니다. 리졸버의 N+1을 잡는 DataLoader 패턴, POST 기반 캐싱 한계를 보완하는 Persisted Queries, 그리고 악성 쿼리를 막는 Depth Limit·Complexity Limit입니다. REST 쪽 타입 안전성을 비교하고 싶다면 OpenAPI(Swagger)와 tRPC 문서를 함께 보면 두 진영의 도구 생태계가 한눈에 잡힙니다.
차이는 데이터 형태를 누가 정하느냐 한 가지로 압축됩니다. REST는 서버가 엔드포인트별 응답 형태를 고정하고, GraphQL은 클라이언트가 필요한 필드만 쿼리로 지정합니다. 이 차이에서 GraphQL은 오버·언더페칭을 기본 해결하고 타입 스키마를 내장하는 대신 캐싱과 N+1, 보안 설정이라는 새 비용을 떠안고, REST는 HTTP 캐싱과 단순함을 가져가는 대신 N+1을 엔드포인트 설계로 직접 회피해야 합니다. 결국 둘은 우열이 아니라 팀 규모·클라이언트 다양성·운영 역량에 따라 골라 쓰거나 BFF로 함께 쓰는 관계입니다.
전체를 한 번에 GraphQL로 갈아엎지 마시고, 캐싱 전략부터 점검하시기를 권합니다. REST에서 Cache-Control과 ETag로 잘 캐싱되던 엔드포인트가 GraphQL의 POST 요청으로 바뀌면 CDN 캐싱이 깨지므로, 이 부분은 Persisted Queries나 Apollo Client 캐시로 대체할 계획을 먼저 세워야 합니다. 현실적인 접근은 마이크로서비스 내부 통신은 REST로 유지하고, 클라이언트에 노출되는 레이어만 BFF(Backend For Frontend)나 GraphQL Federation으로 점진적으로 감싸는 방식입니다. 처음부터 전면 전환보다 손실 적은 도입 경로입니다.