← ALL ENTRIES

BFF 패턴 (Backend for Frontend)


한 줄 정의

각 클라이언트(웹, 모바일, 앱 등) 전용 백엔드를 별도로 두는 아키텍처 패턴

왜 필요한가? — 문제에서 출발하기

API를 리소스 중심으로 잘게 분리하면 유연성은 올라가지만, 클라이언트 입장에서는 고통이 생긴다.

예를 들어 “사용자 프로필 화면”을 그리려면:

  1. GET /users/{id} → 유저 기본 정보
  2. GET /users/{id}/posts → 작성 게시글
  3. GET /users/{id}/followers → 팔로워 목록

이렇게 3번의 요청을 순차적으로 보내야 한다. 이게 바로 Waterfall 문제다. 앞 요청의 응답을 받아야 다음 요청을 보낼 수 있어서, 응답 시간이 누적된다.

게다가 클라이언트마다 필요한 데이터가 다르다:

  • 웹 브라우저: 고해상도 이미지, 풍부한 데이터 → 네트워크 여유 있음
  • 모바일 앱: 저해상도 썸네일, 최소한의 데이터 → 네트워크·배터리 절약이 중요
  • IoT 디바이스: 극단적으로 가벼운 데이터만 필요

범용 API 하나로 이 모든 클라이언트를 만족시키려면, 결국 가장 많은 데이터를 필요로 하는 클라이언트 기준으로 설계하게 된다. 모바일은 필요 없는 데이터까지 받아서 파싱해야 하고, 이는 낭비다.

BFF 패턴의 구조

          ┌─────────────┐
          │   Web App   │
          └──────┬──────┘

          ┌──────▼──────┐
          │  Web BFF    │ ← 웹 전용 백엔드
          └──────┬──────┘

┌────────────────▼────────────────────┐
│           내부 마이크로서비스들         │
│  Users API / Posts API / Feed API  │
└────────────────┬────────────────────┘

          ┌──────▼──────┐
          │ Mobile BFF  │ ← 모바일 전용 백엔드
          └──────┬──────┘

          ┌──────▼──────┐
          │  Mobile App │
          └─────────────┘

BFF는 클라이언트와 내부 서비스 사이의 중간 계층이다. 각 BFF는:

  • 여러 내부 API를 조합·집계해서 클라이언트가 원하는 형태로 가공
  • 클라이언트가 1번의 요청으로 필요한 데이터를 한 번에 받을 수 있게 함
  • 클라이언트별로 최적화된 응답 제공 (웹은 풀 데이터, 모바일은 경량 데이터)

BFF가 해결하는 문제들

1. Waterfall 문제 해소

클라이언트가 여러 API를 순서대로 호출하는 대신, BFF가 내부적으로 병렬로 호출하고 결과를 합쳐서 1번의 응답으로 돌려준다.

2. Over-fetching / Under-fetching 해소

  • Over-fetching: 필요 없는 데이터까지 받는 문제 → BFF에서 클라이언트에 맞게 필터링
  • Under-fetching: 데이터가 부족해 추가 요청을 보내야 하는 문제 → BFF에서 미리 조합

3. 클라이언트별 최적화

모바일 BFF는 이미지 URL을 저해상도로 변환하거나, 불필요한 필드를 제거한 응답을 준다. 웹 BFF는 SEO에 맞는 데이터 구조로 제공한다.

4. 클라이언트 변경에 유연

모바일 앱 UI가 바뀌어 필요한 데이터 구조가 달라져도, Mobile BFF만 수정하면 된다. 내부 서비스나 Web BFF에는 영향이 없다.

BFF vs 범용 API vs GraphQL 비교

방식장점단점
범용 API단순, 관리 포인트 하나Over/Under-fetching, 클라이언트별 최적화 불가
BFF클라이언트별 최적화, 관심사 분리BFF 수만큼 유지보수 포인트 증가
GraphQL클라이언트가 필요한 필드만 요청 가능학습 곡선, N+1 문제, 캐싱 어려움

GraphQL은 BFF의 대안으로 자주 언급된다. 클라이언트가 쿼리로 원하는 데이터 구조를 직접 명시하면, 서버가 그에 맞춰 응답하기 때문이다. 다만 캐싱이 어렵고 N+1 문제가 생기는 등 복잡성이 있어, BFF와 GraphQL을 함께 쓰는 구조도 존재한다.

실제 사례

  • Netflix: 디바이스(TV, 모바일, 웹)마다 BFF를 두고 최적화된 응답 제공
  • SoundCloud: 모바일 앱 전용 BFF를 도입해 응답 시간과 데이터 크기를 대폭 줄임 (BFF 패턴이 처음 공식 정의된 사례)
  • Spotify: 마이크로서비스 + BFF 조합

API 설계와의 관계

리소스 중심으로 API를 잘게 분리하면 내부 서비스의 유연성은 올라가지만, 클라이언트의 부담이 커진다. BFF는 이 둘을 동시에 만족시키는 방법이다.

클라이언트 ←→ BFF (클라이언트별 최적화) ←→ 내부 API (리소스 중심 분리)

즉, 내부는 잘게 쪼개고, 외부 인터페이스는 BFF로 통합하는 전략이다.

언제 도입할까?

도입이 적합한 경우:

  • 클라이언트 종류가 2개 이상이고 필요한 데이터가 명확히 다를 때
  • 마이크로서비스 아키텍처를 사용할 때
  • 클라이언트 팀이 BFF를 직접 관리할 수 있을 때 (프론트엔드가 BFF 코드를 소유)

굳이 안 해도 되는 경우:

  • 클라이언트가 하나뿐이거나 데이터 요구사항이 유사할 때
  • 팀이 작아서 BFF를 추가로 유지보수하기 부담스러울 때