Backend For Frontend
Backend for Frontend (BFF) is a dedicated backend service per client type (web, iOS, Android) that aggregates microservice calls and shapes responses for that client's UX needs.
Introduction
Backend for Frontend (BFF) is a dedicated backend service per client type (web, iOS, Android) that aggregates microservice calls and shapes responses for that client's UX needs. Airbnb's listing search page composes pricing, availability, photos, and reviews via a GraphQL BFF — not 9 round trips from the mobile app.
Real production story
Airbnb's 2016 mobile app made 11 REST calls to render a listing detail screen — serial on 3G, parallel on WiFi with battery drain from radio wake. Product wanted skeleton loading states and field-level cache; backend teams wanted stable service contracts without mobile-driven API bloat.
The mobile BFF team shipped a GraphQL layer (later complemented by dedicated REST BFFs) that orchestrated Listing, Pricing, Calendar, and Review services in one server round trip. Web BFF returned SEO-friendly HTML-oriented payloads; iOS BFF returned image URL sizes matched to device resolution. Core domain services stayed client-agnostic — BFF absorbed presentation variance.
Business problem
Business pressure: Airbnb's guest experience varies by platform — mobile needs lean JSON and aggressive caching; web needs SEO metadata — one generic API serves neither well.
- Revenue at risk: Slow listing page load on mobile reduces booking conversion — 300ms delay measurably drops completion.
- Engineering velocity: Mobile and web teams blocked on same API versioning debates — BFF decouples client release cycles.
- Compliance / trust: Guest PII minimized per client — BFF strips fields mobile does not need.
Architecture overview
One BFF per client type — not one BFF per screen and not one universal BFF for all clients. BFF orchestrates, aggregates, caches; domain services enforce business rules.
- Definition: Client-adjacent backend that composes domain services into client-optimal responses.
- When to adopt: 3+ microservice calls per screen; materially different client payloads.
- When to defer: Single client, simple CRUD — API gateway direct routing sufficient.
- Operability: BFF gets client-experience SLO; circuit breakers per upstream service.
Architecture motivation
Why architects care: BFF prevents domain services from accumulating client-specific endpoints (/listings?mobile=true&web_v2=...) — the API explosion anti-pattern.
- Force: Multiple client form factors with different data shape and latency needs.
- Constraint: Domain services must remain reusable across channels and partners.
- Outcome: Client team owns BFF; domain team owns core APIs.
Internal architecture
Airbnb multi-BFF architecture:
┌─────────┐ ┌─────────┐ ┌─────────┐│ iOS App │ │ Web App │ │ Partner │└────┬────┘ └────┬────┘ └────┬────┘│ │ │▼ ▼ ▼┌─────────┐ ┌─────────┐ ┌─────────┐│ Mobile │ │ Web │ │ Partner ││ BFF │ │ BFF │ │ BFF ││ GraphQL │ │ REST+SEO│ │ OpenAPI │└────┬────┘ └────┬────┘ └────┬────┘│ │ │└────────────┼────────────┘▼┌──────────────────────┐│ Domain microservices ││ Listing │ Pricing │ Cal │└──────────────────────┘Domain services: NO mobile-specific fieldsBFF: image width, field selection, batching
Data flow
Primary path: iOS GraphQL query listingDetail(id) → Mobile BFF parses selection set → parallel gRPC to Listing, Pricing, Calendar → merges with device-appropriate photo URLs → single JSON response in 120ms p99.
- Write path: BFF validates client input shape, forwards domain command to authoritative service — BFF does not own booking rules.
- Read path: BFF caches denormalized listing cards in Redis keyed by locale + device class.
- Partial failure: BFF returns listing with pricing unavailable stub — degraded UX, not 500 for entire page.
System design diagram
Two diagrams show the Backend For Frontend topology and the primary request/event path used in production at scale.
Production code example
GraphQL BFF with parallel upstream fetch and partial failure — Airbnb-style:
// mobile-bff/src/resolvers/listingDetail.tsexport const listingDetailResolver = {Query: {listingDetail: async (_: unknown, { id }: { id: string }, ctx: Context) => {const [listing, pricing, calendar, reviews] = await Promise.allSettled([ctx.clients.listing.get(id),ctx.clients.pricing.getQuote(id, ctx.locale),ctx.clients.calendar.getAvailability(id, ctx.dateRange),ctx.clients.reviews.getSummary(id),]);if (listing.status === "rejected") throw new NotFoundError(id);return {...mapListingForMobile(listing.value, ctx.deviceClass),pricing: pricing.status === "fulfilled"? pricing.value: { unavailable: true },availability: calendar.status === "fulfilled"? calendar.value: [],reviews: reviews.status === "fulfilled"? reviews.value: { count: 0, average: null },};},},};// GraphQL depth limit + complexity scoring at server middlewareapp.use(graphqlProtection({ maxDepth: 8, maxComplexity: 1200 }));
Enterprise case study
Airbnb listing detail BFF (2016–2019): Reduced mobile listing page load from 11 sequential calls to 1; conversion uplift measurable on 3G markets.
- Before: Client orchestrated 11 REST calls; fragile error handling; API versioning fights.
- Decision: Per-platform BFF with GraphQL (mobile), dedicated aggregation layer, strict no-domain-logic rule.
- After: p99 listing detail 120ms; domain services stable; mobile/web release independently.
Trade-offs
- Client optimization vs duplication: Three BFFs mean three orchestration codebases — shared client SDK for upstream calls mitigates.
- BFF logic creep: Business rules drift into BFF — code review must reject domain logic outside services.
- Latency vs chattiness: BFF adds hop but removes N client round trips — net win on mobile networks.
Security considerations
Security is architectural: BFF is trust boundary between client and internal mesh — validates client tokens, forwards service identity internally.
- Identity: BFF validates guest JWT; upstream calls use service account — client never holds internal creds.
- Data: BFF filters PII from responses — mobile gets masked phone, web gets none.
- GraphQL: Query depth/complexity limits prevent malicious deep queries at BFF.
Scalability analysis
Scale dimensions: Airbnb BFF autoscales on RPS per client type; search-heavy BFF gets separate fleet from booking BFF.
- Horizontal scale: Stateless BFF replicas; cache hot listing data at BFF edge.
- Hot spots: Popular city listing queries — BFF cache + CDN for static listing facets.
- Cost: BFF CPU for aggregation — cheaper than mobile battery and data costs from chattiness.
Failure scenarios
What breaks: BFF becomes domain service with extra steps; upstream timeout without partial response.
- Thundering herd: BFF cache miss fans out 11 parallel calls per user — stampede upstream; use request coalescing.
- Logic leak: Discount rules implemented in BFF and Pricing service — divergent prices; reject in review.
- Universal BFF: One BFF for iOS + web + partners — reintroduces API explosion via flags.
Staff engineer insights
- BFF owner should be the client team (mobile guild), not the platform team — they feel latency pain directly.
- Airbnb lesson: if BFF and domain service both implement pricing rules, you have two sources of truth — fire one.
- Partial failure response design is the BFF staff interview question — show degraded JSON, not cascade 500.
Interview questions
Interview Prep
Practice concise answers, then expand each card for the explanation.
1AdvancedQuestionWhat is the difference between API Gateway and BFF?+
Answer
Follow-up
2AdvancedQuestionWhy one BFF per client type instead of one universal BFF?+
Answer
Follow-up
3AdvancedQuestionHow do you handle partial upstream failure in a BFF?+
Answer
Follow-up
Architecture review questions
- Is there a separate BFF per major client type (mobile, web), not one universal BFF?
- Does BFF contain zero domain business rules (orchestration only)?
- Are upstream calls parallelized with partial failure handling?
- Are GraphQL depth/complexity limits enforced if using GraphQL?
- Is BFF owned by the client team with client-experience SLO?
- Are domain services free of client-specific fields and query parameters?
Summary
Backend for Frontend at Airbnb scale gives each client platform a dedicated aggregation layer that composes domain microservices into optimal responses. Staff architects assign BFF ownership to client teams, enforce no domain logic in BFF, and design partial failure as degraded UX rather than cascade outages.