Backend for Frontend (BFF) là một dịch vụ backend chuyên biệt cho một frontend cụ thể. Thay vì web, iOS, Android và tích hợp bên thứ ba cùng gọi một backend đa năng, mỗi client có một lớp server riêng để tổng hợp, lọc và định hình dữ liệu từ microservice thành đúng payload mà giao diện đó cần.
Sam Newman đặt tên và phổ biến mô hình này vào năm 2015, dựa trên công việc tại SoundCloud. Đến nay, BFF vẫn là một mô hình phổ biến cho các nhóm chạy microservice phía sau nhiều ứng dụng client, và Microsoft cũng tài liệu hóa nó như một mô hình kiến trúc đám mây cốt lõi.
Vấn đề mà BFF giải quyết
Giả sử hệ thống ban đầu chỉ có một web app và một backend REST. Sau đó bạn thêm mobile app, tích hợp đối tác, rồi smartwatch app. Tất cả client bắt đầu gọi cùng một backend, trong khi mỗi client cần dữ liệu khác nhau.
Hai vấn đề thường xuất hiện:
1. Over-fetching và under-fetching
Một endpoint đa năng thường trả về một cấu trúc cố định.
- Web dashboard cần hồ sơ khách hàng đầy đủ, lịch sử đơn hàng, gợi ý và cài đặt tài khoản.
- Mobile app trên mạng yếu chỉ cần
name,avatarUrl,unreadCount.
Nếu cả hai dùng cùng endpoint, mobile phải tải quá nhiều dữ liệu hoặc phải gọi thêm nhiều endpoint khác để ghép dữ liệu.
2. Client gọi quá nhiều request
Một màn hình home trên mobile có thể cần:
- thông tin user
- số thông báo chưa đọc
- feed mới nhất
- trạng thái subscription
Nếu client tự gọi 3–4 microservice rồi ghép dữ liệu trên thiết bị, bạn sẽ gặp:
- latency cao hơn
- tốn pin hơn
- logic orchestration nằm trong app
- khó test và versioning hơn
BFF chuyển phần orchestration này lên server, nơi dễ kiểm thử, quan sát và triển khai hơn.
Mô hình BFF hoạt động như thế nào
BFF là một lớp server mỏng nằm giữa frontend và các service phía dưới.
[ Ứng dụng Web ] ---> [ Web BFF ] ---\
[ Ứng dụng iOS ] ---> [ iOS BFF ] -----> [ Microservice ]
[ Ứng dụng Android ] ---> [ Android BFF ] ---/
Mỗi BFF thường làm ba việc chính.
1. Aggregate: tổng hợp dữ liệu
BFF gọi nhiều service downstream và trả về một response duy nhất cho client.
Ví dụ mobile app chỉ gọi:
GET /mobile/home
Thay vì tự gọi:
GET /users/me
GET /notifications/count
GET /feed
GET /subscriptions/current
Ví dụ đơn giản bằng Node.js/Express:
app.get("/mobile/home", async (req, res, next) => {
try {
const userId = req.user.id;
const [profile, notifications, feed] = await Promise.all([
userService.getProfile(userId),
notificationService.getUnreadCount(userId),
feedService.getLatest(userId),
]);
res.json({
user: {
name: profile.name,
avatarUrl: profile.avatarUrl,
},
unreadCount: notifications.count,
feed: feed.items.slice(0, 10),
});
} catch (err) {
next(err);
}
});
Đây là API aggregation áp dụng cho một trải nghiệm người dùng cụ thể. Nếu bạn muốn hiểu phiên bản tổng quát hơn, xem bài về mô hình API aggregator.
2. Reshape: định hình lại payload
BFF cắt bớt field, đổi tên field, làm phẳng object lồng nhau và định dạng dữ liệu theo cách client cần.
Ví dụ service trả về:
{
"id": "u_123",
"first_name": "An",
"last_name": "Nguyen",
"profile": {
"avatar": {
"url": "https://cdn.example.com/a.png"
}
},
"internal_flags": {
"risk_score": 12
}
}
Mobile BFF có thể trả về:
{
"id": "u_123",
"displayName": "An Nguyen",
"avatarUrl": "https://cdn.example.com/a.png"
}
Client nhận đúng dữ liệu cần dùng, không phải biết cấu trúc nội bộ của service.
3. Translate: phiên dịch theo nhu cầu client
BFF cũng có thể xử lý các khác biệt theo client như:
- phân trang kiểu cursor cho mobile
- cache response ngắn hạn cho màn hình home
- chuyển đổi protocol
- chuẩn hóa error message cho UI
- gom nhiều error downstream thành một response dễ xử lý
Các microservice phía dưới vẫn giữ tính đa năng và không phụ thuộc frontend. BFF là nơi đặt logic định hình dành riêng cho client. Nếu bạn mới làm quen với tầng service bên dưới, xem thêm microservice so với API và quá trình từ monolith sang microservice.
Một BFF cho mỗi trải nghiệm client
Nguyên tắc ngắn gọn của Newman là: một trải nghiệm, một BFF.
Nếu iOS và Android có trải nghiệm khác nhau rõ rệt, hãy tách BFF. Nếu web và mobile cần payload khác nhau, cũng nên tách.
Web UI -> Web BFF
iOS App -> iOS BFF
Android App -> Android BFF
Partner API -> Partner BFF
Mục tiêu là giữ mỗi BFF nhỏ và tập trung. Khi một BFF bắt đầu chứa nhiều nhánh như:
if (client === "mobile") {
// return compact payload
} else if (client === "web") {
// return full payload
}
nó đang quay lại thành backend đa năng, đúng vấn đề mà BFF muốn tránh.
Có ngoại lệ hợp lý: nếu cùng một nhóm sở hữu iOS và Android, và hai app có trải nghiệm gần như giống nhau, một Mobile BFF dùng chung có thể đủ. Tiêu chí quyết định là quyền sở hữu và mức độ giống nhau của trải nghiệm, không chỉ tên nền tảng.
Quyền sở hữu thuộc về nhóm frontend
BFF nên thuộc về nhóm sở hữu frontend tương ứng.
Điều này có nghĩa:
- nhóm web sở hữu Web BFF
- nhóm mobile sở hữu Mobile BFF
- nhóm partner integration sở hữu Partner BFF
Lợi ích thực tế:
- frontend và BFF có thể release cùng nhịp
- nhóm frontend tự ưu tiên backlog API cho UI
- không phải chờ một nhóm backend chung thêm endpoint
- logic phục vụ UI nằm gần nhóm hiểu UI nhất
BFF di chuyển ranh giới quyết định dành riêng cho client về đúng nhóm chịu trách nhiệm cho client đó. Đây cũng là cách tầng “experience” trong kết nối dựa trên API thường được tổ chức.
BFF so với API Gateway
BFF và API gateway đều nằm giữa client và service, nên dễ bị nhầm lẫn. Nhưng chúng giải quyết hai vấn đề khác nhau.
API gateway là điểm vào chung cho toàn bộ traffic. Nó thường xử lý:
- authentication
- rate limiting
- routing
- TLS termination
- logging
- monitoring
Gateway nên trung lập với client.
BFF thì ngược lại. Nó được thiết kế riêng cho một client hoặc một trải nghiệm. Nó xử lý payload shape, orchestration và nhu cầu UI cụ thể.
Một bố cục phổ biến trong production:
Client
|
v
API Gateway
|
+--> Web BFF
+--> Mobile BFF
+--> Partner BFF
|
v
Microservices
Dùng gateway cho phần giống nhau giữa mọi client. Dùng BFF cho phần khác nhau giữa các client.
Để hiểu thêm về gateway, xem các so sánh: API management so với API gateway, API gateway so với bộ cân bằng tải, và service mesh so với API gateway.
Khi nào nên sử dụng BFF
BFF phù hợp khi bạn có một hoặc nhiều điều kiện sau.
Bạn có nhiều client thực sự khác nhau
Ví dụ:
- web dashboard cần dữ liệu đầy đủ
- mobile app cần response nhẹ
- partner API cần schema ổn định và khác với UI
- smartwatch chỉ cần vài field
Trải nghiệm càng khác nhau, BFF càng hữu ích.
Backend chung đã thành nút thắt cổ chai
Nếu mọi thay đổi UI đều cần thương lượng với nhiều nhóm backend, BFF giúp tách phần định hình dữ liệu theo client ra khỏi backend chung.
Bạn cần payload tối ưu cho từng client
Mobile có thể cần response nhỏ, cache tốt và ít round-trip. Web có thể cần payload phong phú hơn. BFF cho phép tối ưu từng loại mà không buộc service phía dưới phục vụ mọi trường hợp.
Một runtime phù hợp hơn với frontend
Một nhóm có thể viết BFF bằng runtime quen thuộc với họ, miễn là vẫn tuân thủ tiêu chuẩn vận hành chung của tổ chức.
Khi nào không nên sử dụng BFF
BFF không miễn phí. Đừng thêm BFF nếu nó chỉ làm kiến trúc phức tạp hơn.
Bạn chỉ có một client
Nếu hệ thống chỉ có một frontend, BFF thường chỉ là một hop thừa. Một backend thông thường có thể đủ.
Các client dùng dữ liệu gần như giống nhau
Nếu web và mobile cần cùng schema, cùng field, cùng behavior, tách BFF có thể chỉ tạo trùng lặp.
GraphQL đã giải quyết vấn đề payload shaping
GraphQL cho phép client query đúng field cần dùng từ một endpoint. Điều này có thể giải quyết over-fetching và under-fetching mà không cần BFF riêng.
Nếu bạn đã có GraphQL server với resolver phù hợp cho frontend, một tầng BFF riêng có thể không thêm nhiều giá trị. Xem thêm GraphQL là gì trước khi thêm BFF.
Gateway cộng microservice đã đủ
Với hệ thống đơn giản, API gateway phía trước các microservice được thiết kế tốt có thể đáp ứng nhu cầu mà không cần một tầng riêng cho từng client.
Những nhược điểm thực tế
Ngay cả khi BFF là lựa chọn đúng, bạn vẫn cần quản lý các chi phí sau.
Trùng lặp mã
Nhiều BFF có thể cùng cần:
- xác thực token
- format ngày giờ
- mapping lỗi
- gọi cùng một service downstream
Cách xử lý:
- đưa logic dùng chung vào library nội bộ
- để gateway xử lý việc chung như authentication, rate limiting, monitoring
- giữ BFF tập trung vào logic dành riêng cho client
Không nên biến BFF thành nơi chứa business logic cốt lõi.
Nhiều service hơn để vận hành
Mỗi BFF có:
- pipeline riêng
- deployment riêng
- monitoring riêng
- quyền truy cập riêng
- surface bảo mật riêng
Trước khi thêm BFF, hãy chắc rằng nhóm có khả năng vận hành nó.
Thêm một network hop
Client không gọi thẳng microservice nữa mà gọi BFF trước. Điều này thêm một hop mạng.
Tuy nhiên, trong nhiều trường hợp BFF vẫn giảm tổng latency vì thay thế nhiều request client-to-service bằng một request client-to-BFF, sau đó BFF gọi các service song song.
Hãy đo thay vì giả định.
BFF có thể trở nên cồng kềnh
BFF không nên:
- phục vụ quá nhiều client khác nhau
- chứa nhiều nhánh
if client_type - sở hữu business capability
- thay thế microservice
Nếu BFF phình to, hãy tách lại theo trải nghiệm hoặc đẩy logic nghiệp vụ về service phù hợp.
Cách triển khai BFF theo hướng thực tế
Một quy trình triển khai BFF an toàn có thể đi theo các bước sau.
Bước 1: Chọn một màn hình hoặc flow cụ thể
Đừng bắt đầu bằng “xây Mobile BFF cho toàn app”. Hãy chọn một use case rõ ràng, ví dụ:
Mobile Home Screen
Liệt kê dữ liệu màn hình cần:
- user display name
- avatar URL
- unread notification count
- latest 10 feed items
Bước 2: Xác định các service downstream
Ví dụ:
User Service -> profile
Notification Service -> unread count
Feed Service -> latest feed
Bước 3: Thiết kế contract của BFF
Ví dụ endpoint:
GET /mobile/home
Response:
{
"user": {
"displayName": "An Nguyen",
"avatarUrl": "https://cdn.example.com/a.png"
},
"unreadCount": 3,
"feed": [
{
"id": "post_1",
"title": "Hello BFF",
"publishedAt": "2026-07-01T10:00:00Z"
}
]
}
Bước 4: Implement orchestration
Ví dụ với Express:
app.get("/mobile/home", authenticate, async (req, res, next) => {
try {
const userId = req.user.id;
const [profile, unread, feed] = await Promise.all([
userService.getProfile(userId),
notificationService.getUnreadCount(userId),
feedService.getLatest(userId, { limit: 10 }),
]);
res.json({
user: {
displayName: `${profile.firstName} ${profile.lastName}`,
avatarUrl: profile.avatarUrl,
},
unreadCount: unread.count,
feed: feed.items.map((item) => ({
id: item.id,
title: item.title,
publishedAt: item.publishedAt,
})),
});
} catch (error) {
next(error);
}
});
Bước 5: Thêm timeout và fallback
BFF không nên treo toàn bộ màn hình chỉ vì một service chậm. Ví dụ feed có thể fallback về mảng rỗng, nhưng profile thì bắt buộc.
const feed = await feedService
.getLatest(userId, { limit: 10, timeoutMs: 500 })
.catch(() => ({ items: [] }));
Bước 6: Test contract
Kiểm tra ít nhất:
- response đúng schema
- không leak field nội bộ
- downstream error được map đúng
- timeout không làm hỏng toàn bộ response nếu field đó optional
- versioning rõ ràng khi payload thay đổi
Giữ cho các hợp đồng BFF đồng bộ với Apidog
Phần khó khi chạy BFF trong thực tế là contract. Mỗi BFF cung cấp API riêng cho client của nó và đồng thời phụ thuộc vào contract của các microservice bên dưới. Khi các contract này lệch nhau, lỗi thường xuất hiện ở client.
Đây là nơi Apidog phù hợp với quy trình làm việc. Apidog là nền tảng thiết kế, kiểm thử, giả lập và tài liệu API, giúp contract của từng BFF có một nơi chung để frontend và backend cùng làm việc.
Bạn có thể áp dụng theo cách sau:
1. Thiết kế contract trước
Định nghĩa endpoint, request schema và response schema của BFF trước khi viết code. Apidog dùng OpenAPI bên dưới, phù hợp với cách làm thiết kế API dựa trên hợp đồng và giúp hợp đồng API rõ ràng.
2. Mock BFF trước khi service sẵn sàng
Frontend có thể bắt đầu tích hợp với mock API sau khi contract được thống nhất, ngay cả khi BFF hoặc service downstream chưa hoàn tất.
3. Kiểm thử contract
Dùng test và validation để đảm bảo BFF trả về đúng payload mà client mong đợi. Điều này đặc biệt hữu ích trong CI, khi một thay đổi downstream có thể làm response của BFF sai schema.
4. Tạo tài liệu cho cả hai phía
Tài liệu tương tác giúp:
- frontend biết cách gọi BFF
- backend biết BFF đang phụ thuộc vào contract nào
- các nhóm có cùng một nguồn thông tin đáng tin cậy
Lưu ý phạm vi: Apidog không xây dựng, lưu trữ hoặc chạy BFF của bạn, và cũng không phải API gateway. Nó là nơi thiết kế, mock, test và tài liệu hóa contract API phía sau mỗi BFF. Xem mỗi BFF như một sản phẩm với contract ổn định là cách giúp mô hình này bền vững.
Câu hỏi thường gặp
BFF có phải là microservice không?
BFF là một service phía server và trong kiến trúc microservice, nó thường được triển khai như một microservice. Nhưng vai trò của nó khác microservice nghiệp vụ.
- Microservice sở hữu một capability nghiệp vụ.
- BFF sở hữu trải nghiệm của một client.
BFF là service ở tầng experience, không phải service nghiệp vụ cốt lõi.
Tôi nên có bao nhiêu BFF?
Mặc định: một BFF cho mỗi trải nghiệm client riêng biệt.
Ví dụ:
Web BFF
iOS BFF
Android BFF
Partner BFF
Chỉ gộp BFF khi cùng một nhóm sở hữu các client có nhu cầu gần như giống nhau. Tách ra khi một BFF bắt đầu có nhiều logic điều kiện theo client.
GraphQL có thay thế BFF không?
Có thể, nếu vấn đề chính của bạn là payload shaping. GraphQL giúp client lấy đúng field cần dùng từ một endpoint.
BFF vẫn hữu ích nếu bạn cần:
- orchestration riêng cho client
- translation protocol
- runtime riêng
- caching strategy riêng
- release cycle gắn với một frontend cụ thể
Có thể dùng BFF và API gateway cùng nhau không?
Có. Đây là cách rất phổ biến.
API gateway xử lý phần chung:
- authentication
- rate limiting
- monitoring
- routing
BFF xử lý phần riêng của từng client:
- aggregate
- reshape
- translate
- chuẩn hóa response cho UI
Ai nên sở hữu BFF?
Nhóm frontend sở hữu client nên sở hữu BFF tương ứng. Đây là điểm cốt lõi của mô hình, vì nó cho phép nhóm thay đổi UI và endpoint hỗ trợ cùng nhau.
BFF có làm tăng độ trễ không?
BFF thêm một network hop, nên có chi phí. Nhưng nó cũng có thể giảm tổng latency vì client gọi ít request hơn và BFF có thể gọi service downstream song song.
Cách đúng là đo:
- latency trước và sau khi thêm BFF
- số request từ client
- payload size
- error rate
- thời gian render màn hình
Nếu BFF giảm round-trip và payload đủ nhiều, chi phí thêm một hop thường là đánh đổi hợp lý.

Top comments (0)