Give each type of client its own dedicated backend, shaped for exactly what that client needs, instead of one generic API serving all of them.
A mobile app wants a small, pre-aggregated payload to save battery and bandwidth. A web dashboard wants rich, deeply nested data for a complex table. A single shared API tuned for one of them tends to under-serve or over-fetch for the other, and compromise requests from a third client (e.g. a partner integration) pull it in yet another direction.
Instead of one API for every client, each client type — mobile, web, partner — gets its own thin backend, owned often by the same team that owns that client. Each BFF calls the shared downstream services and shapes the response specifically for its one client, with no obligation to serve anyone else well.
Both BFFs call the same underlying services, but each returns a payload shaped for its own client's needs — mobile gets a slim summary, web gets full detail.
const productService = { get: (id) => ({ id, name: "Mouse", price: 29.99, description: "...", stock: 42, sku: "M-1" }) };
const reviewsService = { get: (id) => ({ id, rating: 4.5, reviews: ["great", "solid"] }) };
// Mobile BFF: small payload, minimal fields.
function mobileBFF(id) {
const p = productService.get(id);
return { id: p.id, name: p.name, price: p.price };
}
// Web BFF: full detail for a rich dashboard.
function webBFF(id) {
const p = productService.get(id);
const r = reviewsService.get(id);
return { ...p, rating: r.rating, reviews: r.reviews };
}
console.log(mobileBFF("sku-1"));
console.log(webBFF("sku-1"));