BFF (Backend For Frontend) concept page: per-client backend layer (web BFF, mobile BFF, GraphQL gateway alternative, partner public API) sitting between clients and domain microservices. Three scenarios: web BFF aggregates 5 microservice calls into single typed response with edge cache; mobile BFF returns lighter payload (3KB vs 12KB); GraphQL gateway alternative with DataLoader. Plus anti-patterns scenario for timeouts/circuit breakers. Includes ADR comparing BFF per-client vs single GraphQL gateway vs API Gateway.
Generic API, который обязан обслуживать web, iOS, Android, smart TV и партнерские интеграции, почти всегда оптимизирован ни для кого. Вебу нужны одни поля и крупные payload, мобильному клиенту - меньше round-trip и компактная форма, TV - совсем другая навигация, партнерам - стабильный semver-контракт. Если все эти клиенты ходят в один общий API или прямо в набор микросервисов, composition logic расползается по приложениям, latency растет, а каждое изменение превращается в очередь тикетов к backend-команде.
Backend For Frontend решает эту организационно-техническую проблему: у каждого класса клиента появляется свой backend слой, который агрегирует, проецирует, кэширует и адаптирует данные под конкретный UI. Термин появился в SoundCloud примерно в 2011 году, но паттерн стал массовым с microservices, mobile-first продуктами и frontend-командами, которые хотят владеть delivery end-to-end.
BFF важно знать не как "еще один gateway", а как границу ответственности. API Gateway отвечает за auth, routing, TLS, rate limit и общие platform concerns. BFF отвечает за форму экрана, round-trip budget и client-specific contract.
API Gateway - это входная дверь платформы. BFF - это кухня конкретного клиента. Gateway не должен знать, что на iOS home screen нужны 3 блока, а на web dashboard - 8 блоков с расширенными полями. BFF знает, потому что им владеет команда клиента.
BFF делает три вещи:
BFF не должен становиться местом доменной логики. Цена, налоги, платежные правила, inventory invariants и permissions должны жить в domain services. BFF собирает и адаптирует, но не заменяет backend domain model.
Диаграмма показывает клиентов слева: web, ios, android, partner. В центре находится BFF layer: bff-web, bff-mobile, gql-gateway как альтернатива и public-api для партнеров. Справа находятся domain microservices: svc-user, svc-catalog, svc-orders, svc-pricing, svc-recs. Отдельно есть edge-cache, потому что часть BFF-ответов может кэшироваться по locale/anonymous variant.
bff-web связан с пятью upstream-сервисами, потому что web home собирает сложный экран. bff-mobile связан только с нужными сервисами и возвращает меньший payload. partner не ходит в web BFF: он использует public-api, потому что BFF может меняться вместе с UI-релизами, а партнерский контракт должен быть стабильным.
ADR-001 на bff-web сравнивает BFF per client, single GraphQL gateway и generic API Gateway. Это центральная точка урока: BFF - не универсальный ответ, а выбор при нескольких клиентах с разной формой данных и latency constraints.
web-bff-aggregate показывает один GET /home из браузера. Web BFF проверяет edge cache, пропускает authenticated variant и параллельно вызывает user, catalog, orders, recommendations и pricing. Затем возвращает 12KB JSON с нужными полями. Урок: BFF уменьшает количество browser round-trip и убирает data composition из клиента. Но upstream fan-out теперь надо защищать timeout, bulkhead и circuit breaker.
mobile-bff-light показывает мобильный endpoint. iOS и Android используют один mobile BFF, который вызывает меньше upstream и возвращает около 3KB: компактный user, последние orders и prices. Recommendations, HD avatar и глубокие catalog fields не нужны на этом экране. Урок: mobile optimization - это не только сжатие, а другая форма данных и другой latency budget.
graphql-alternative показывает single GraphQL gateway. Клиент сам выбирает поля, resolvers ходят в несколько сервисов, DataLoader batch/dedup снижает N+1. Урок: GraphQL хорошо решает overfetching и field selection, но создает центральную schema ownership и resolver performance риски. Он может быть альтернативой BFF или жить внутри BFF.
bff-failure-modes показывает деградацию recommendations service до p99=12s. Без timeout весь BFF блокируется, TTFB страницы становится 12 секунд. После фикса BFF ставит 200ms timeout, circuit breaker и возвращает fallback для recs, сохраняя основной экран быстрым. Урок: BFF повышает удобство клиента, но также становится точкой каскадных отказов, если не задать жесткие upstream budgets.
BFF per client дает автономию frontend-команде, меньший payload, меньше round-trip, независимые релизы формы API и возможность адаптировать auth/session под клиента. Цена - дополнительный deployment unit, observability, on-call, тесты контрактов и риск дублировать логику между web/mobile BFF.
Single GraphQL gateway дает один endpoint и self-service выбор полей, но требует сильной schema governance, resolver performance дисциплины, DataLoader, depth/complexity limits и ясного ownership. Он хорошо подходит, когда клиенты похожи и главная боль - overfetching, а не разные screen contracts.
Generic API Gateway без BFF хорош, когда один клиент или все клиенты действительно используют один contract. Для простого CRUD BFF будет лишним слоем. Для пяти разных клиентских поверхностей без BFF каждая команда начнет писать свой composition слой внутри app, и продукт получит скрытый BFF без observability.
ADR из диаграммы принимает BFF per client при трех условиях: есть 2+ разных client classes, frontend-команды могут владеть сервисом, а mobile/web latency не выдерживает нескольких последовательных round-trip. Обязательные условия: upstream timeouts, circuit breakers, запрет доменной логики в BFF, version-pin BFF deploy к client app release там, где rollback клиента сложен.
SoundCloud ввел термин BFF, когда generic public API начал мешать mobile delivery. Netflix масштабировал идею для разных device classes и исторически использовал Falcor как client-friendly data layer до массового GraphQL. Spotify и Stripe имеют per-surface backend слои для web/mobile/dashboard. GitHub Rails backend часто играет роль BFF для UI: server собирает форму страницы, а не отдает generic objects. Airbnb использовал GraphQL-подход как клиентский data gateway. Shopify Hydrogen сочетает storefront UI и BFF-like server routes вокруг Storefront API.
В современных Next.js/Remix приложениях BFF часто спрятан в route handlers, loaders, server actions или server components. Это не отменяет паттерн: если слой агрегирует domain services под конкретную UI surface, это BFF, даже если он живет в том же репозитории, что и frontend.
Не используйте BFF, если у вас один клиент и один backend с простой CRUD-моделью. Не используйте BFF как замену API Gateway для TLS/auth/rate limiting - это разные уровни. Не используйте BFF, если команда не готова владеть production service: деплой, мониторинг, алерты, SLO, rollback и security review. Не используйте BFF для партнерского публичного API, который требует долгоживущего стабильного контракта. Не используйте BFF, чтобы скрыть плохие boundaries микросервисов: если каждый экран требует 20 upstream calls, возможно, проблема в domain decomposition.
Внешние источники: Sam Newman про Backend For Frontend, Phil Calcado/SoundCloud original article, ThoughtWorks Tech Radar, Building Microservices by Sam Newman, GraphQL DataLoader материалы, Next.js Route Handlers и Remix loaders docs.