BFF
Backend for Frontend
프론트엔드별 전용 백엔드 서버. 클라이언트 요구에 최적화된 API 제공.
Backend for Frontend
프론트엔드별 전용 백엔드 서버. 클라이언트 요구에 최적화된 API 제공.
BFF(Backend for Frontend)는 각 프론트엔드 클라이언트(웹, 모바일, IoT 등)에 특화된 전용 백엔드 계층을 두는 아키텍처 패턴입니다. Sam Newman이 2015년 마이크로서비스 맥락에서 제안했으며, 범용 API 대신 클라이언트별 요구사항에 맞춘 API를 제공해 프론트엔드 개발 효율을 높입니다.
BFF의 탄생 배경은 "모든 클라이언트가 같은 API를 쓴다"는 가정의 한계입니다. 웹 앱은 풍부한 데이터가 필요하지만, 모바일은 대역폭 절약을 위해 최소한의 필드만 원합니다. 범용 API로 이를 맞추려면 오버페칭/언더페칭이 발생하고, 프론트엔드에서 불필요한 데이터 가공이 필요합니다.
BFF는 프론트엔드와 백엔드 마이크로서비스 사이에 위치하며, 여러 서비스의 데이터를 집계(aggregation)하고, 클라이언트에 필요한 형태로 변환합니다. 인증/인가 처리, 캐싱, 에러 핸들링도 BFF에서 담당해 프론트엔드 코드를 단순화합니다.
실무에서 BFF는 Next.js의 API Routes, Remix의 loader/action, 또는 별도의 Node.js/Go 서버로 구현합니다. Netflix, Spotify, SoundCloud 같은 대기업에서 모바일/웹/TV 각각 별도 BFF를 운영하며, GraphQL이 BFF 역할을 대체하는 경우도 많습니다.
// Next.js API Route를 BFF로 활용
// pages/api/dashboard.ts (또는 app/api/dashboard/route.ts)
import type { NextApiRequest, NextApiResponse } from 'next';
// 여러 마이크로서비스에서 데이터 집계
async function fetchUserProfile(userId: string) {
const res = await fetch(`${process.env.USER_SERVICE}/users/${userId}`);
return res.json();
}
async function fetchOrders(userId: string) {
const res = await fetch(`${process.env.ORDER_SERVICE}/users/${userId}/orders?limit=5`);
return res.json();
}
async function fetchNotifications(userId: string) {
const res = await fetch(`${process.env.NOTIFICATION_SERVICE}/users/${userId}`);
return res.json();
}
export default async function handler(req: NextApiRequest, res: NextApiResponse) {
const userId = req.headers['x-user-id'] as string;
// 병렬로 여러 서비스 호출
const [profile, orders, notifications] = await Promise.all([
fetchUserProfile(userId),
fetchOrders(userId),
fetchNotifications(userId),
]);
// 클라이언트에 필요한 형태로 변환
res.json({
user: {
name: profile.name,
avatar: profile.avatarUrl,
},
recentOrders: orders.map(o => ({
id: o.id,
total: o.totalAmount,
status: o.status,
})),
unreadCount: notifications.filter(n => !n.read).length,
});
}
"대시보드 페이지에서 5개 API를 호출하는 게 비효율적이에요. BFF 엔드포인트를 하나 만들어서 서버에서 집계하면 클라이언트 코드도 단순해지고, 네트워크 왕복도 줄어들어 로딩이 300ms 정도 빨라질 거예요."
"BFF 패턴은 프론트엔드별 전용 백엔드를 두는 것입니다. 웹과 모바일의 요구사항이 다르면 각각 BFF를 만들어요. 데이터 집계, 형식 변환, 인증 처리를 담당해서 프론트엔드 복잡도를 낮추고, 백엔드 API는 범용성을 유지할 수 있습니다."
"이 데이터 변환 로직을 클라이언트에서 빼고 BFF로 옮기면 좋겠어요. 모바일 앱에서도 같은 로직이 필요할 텐데, 서버에서 한 번만 작성하면 됩니다."
BFF는 집계와 변환만 담당해야 합니다. 비즈니스 로직은 도메인 서비스에 두세요. BFF가 비대해지면 유지보수가 어려워집니다.
웹 BFF와 모바일 BFF가 90% 같은 코드라면 분리할 의미가 없습니다. 공통 라이브러리를 추출하거나 GraphQL 도입을 검토하세요.
BFF는 얇게 유지하고, 프론트엔드 팀이 소유권을 가지세요. 클라이언트 요구사항 변경에 백엔드 팀 의존 없이 빠르게 대응할 수 있습니다.