skip to content

Concretely, what does a BFF do differently when serving a mobile app's product page versus a desktop web app's product page, and how does it accomplish that?

level: middleimportance: must knowfreq 65%

answer

  1. fan-out then compose
  2. concurrent calls, not sequential
  3. payload trimmed per device
  4. view-model shaped response
  5. per-dependency timeout for graceful degradation

basics

~20 s

The BFF talks to the same backend services either way, but it sends the mobile app a smaller, simpler bundle of data (fewer fields, smaller images) and sends the web app a fuller bundle, because phones have less screen space and often slower or costlier networks.

solid answer

~40 s

For each client, the BFF fans out to the relevant downstream services - catalog, pricing, inventory, reviews, and so on - typically in parallel, then composes a response shaped exactly for that UI's view model. Mobile responses are trimmed: fewer fields, smaller image variants, paginated or lazily-loaded sections, to minimize payload size and round trips on constrained networks. Web responses can carry more data since bandwidth and rendering budget are more generous. The BFF also denormalizes or renames fields to match the client's rendering needs directly, so the client doesn't have to transform data before drawing it, and it can apply client-specific caching, feature flags, or A/B test variants without touching the domain services themselves.

go deeper

for a junior

Knows a BFF combines several backend calls into one response for the client.

for a middle

Can describe the fan-out/aggregate/shape mechanism and explain why mobile and web payloads differ.

for a senior

Discusses concurrent calling, per-dependency timeouts, and partial-failure handling concretely.

for a principal

Discusses view-model contract design, how shapes version across client releases, and caching/feature-flag strategy at the BFF layer.

## Fan-out, then compose The core mechanism is **fan-out-then-compose**. When a client requests a screen, the BFF issues calls to each domain service that owns a piece of that screen's data - say: - a **catalog service** for the product description, - a **pricing service** for the price and any discounts, - an **inventory service** for stock status, - and a **reviews service** for the rating summary. These calls are independent of each other, so a well-built BFF issues them concurrently (via async/await, coroutines, or reactive streams) rather than one after another; this matters because sequential calls make total latency the sum of every call, while concurrent calls bound latency to roughly the slowest single call. Once results come back, the BFF composes them into one response object shaped specifically for that client's UI - not a generic "product" resource, but literally the fields that screen's rendering code consumes, in the shape it consumes them. ## Why the shape differs by client The shaping differs by client because the constraints differ by client. - **Mobile.** A mobile device on a cellular connection pays real cost - latency, data usage, sometimes literal money on metered plans - for every extra kilobyte and every extra round trip, so the mobile BFF strips unused fields, sends smaller image variants (or CDN URLs pointing at pre-resized images), and may paginate secondary content like reviews rather than including all of it up front. - **Desktop web.** A desktop web client typically has more bandwidth and a bigger viewport, so its BFF can afford to include a fuller object graph - more review text, higher-resolution images, additional metadata used for SEO or a wider layout. This isn't a difference in what data theoretically exists; it's a difference in what's worth shipping over the wire for that device and screen. ## Reshaping, not only trimming Beyond payload trimming, the BFF also does structural reshaping: - **renaming** backend field names to match the client's view-model naming; - **flattening** nested backend responses into the flatter shape a UI component expects; - **merging** data that lives in two backend services into one field the client renders as a single line (e.g., combining a discount percentage from `pricing-service` with a promotional label from a separate `promotions-service` into one "badge" string). This means client code can bind directly to the response without a transformation layer of its own, which reduces client-side complexity and bugs. Some BFFs go further and hold client-specific caching or feature-flag logic, letting one client see an experimental layout while another doesn't, entirely at the BFF layer without touching the domain services. ## The trade-off The trade-off is that this orchestration work has to be done well, or it becomes the weakest link. - If the BFF calls its four dependencies sequentially instead of concurrently, response time becomes additive and any single slow dependency drags down every request. - If one dependency - say the reviews service - goes down or starts timing out, a BFF without per-dependency timeouts and circuit breakers will hang or fail the entire page rather than degrading gracefully. The correct behavior is to bound each downstream call with its own timeout, treat non-essential data (like reviews) as optional, and return the rest of the page - possibly with a cached or stale version of the missing section - rather than failing the whole request over one slow dependency. This requires the BFF and the client to agree on a contract about which fields are guaranteed versus best-effort, which is a design decision, not something that falls out automatically from adding a BFF. ## A concrete illustration A concrete illustration: an e-commerce product page BFF for a mobile app might return a payload with a thumbnail URL, a two-line truncated description, a price, and a stock boolean, deferring the full review list to a separate paginated call triggered only when the user scrolls to that section. The same BFF's desktop counterpart (or a separate web-BFF) might return the full description, a full-resolution hero image, and the first page of reviews inline, because the web layout has room to show them immediately and the network cost of doing so is acceptable. Both BFFs call the same catalog, pricing, and reviews services underneath - the divergence is entirely in what gets requested, how much of it, and how it's packaged for that specific client.

  • If the BFF makes calls to four downstream services sequentially instead of in parallel, what's the production symptom?
    Latency stacks additively instead of being bounded by the slowest call, so page load time becomes roughly the sum of all four service latencies rather than the max of them. Under load, or when one dependency is degraded, this compounds and can breach latency SLAs even though no single service is individually broken. The fix is issuing independent calls concurrently and only waiting on the ones the response actually needs.
  • How should the BFF handle one of its downstream calls being slow or unavailable, for example the reviews service on a product page?
    It should apply a timeout to that specific call and return the rest of the page without the reviews section, or with a cached/stale version, rather than failing the entire response. This requires per-dependency timeouts or circuit breakers and a clear contract with the client distinguishing required fields from optional, best-effort ones.

Like a restaurant kitchen preparing two different plates from the same pantry ingredients - a compact lunch-to-go box for someone in a hurry, and a fuller sit-down meal for someone with time to spare - portioned and packaged differently even though the ingredients come from the same shelves.

saying these in an interview costs you the question

  • thinks the BFF just proxies one request 1:1 to a single backend service
  • doesn't know payload shaping should differ by device or client
  • assumes sequential calls to downstream services are fine regardless of scale
  • can't describe graceful degradation when one dependency fails
  • treats the BFF's response shape as identical to whatever a domain service already returns

context