PATTERN Cited by 1 source
Unified GraphQL Backend-For-Frontend (UBFF)¶
When to use¶
You have:
- Many frontend surfaces (Web, iOS, Android, partner APIs) consuming roughly the same business data.
- Many backend microservices owning that data (dozens of domains).
- An accumulated cost from a per-surface BFF deployment: duplicated logic, inconsistent customer experience across platforms, fragmented auth/observability, Conway's-Law drift between surfaces (see concepts/backend-for-frontend).
- Capacity to commit to one schema across the company (unified graph discipline), with a dedicated platform team.
- A preference for simpler operations and unified tooling over per-domain deploy independence.
The pattern¶
Deploy a single GraphQL service that:
- Owns one unified schema spanning all product domains.
- Is contributed to by every product team via a shared-ownership monorepo with explicit contribution principles.
- Is consumed by every frontend surface (Web, iOS, Android, partners, internal) through the same endpoint.
- Follows a strict No Business Logic principle — aggregates and shapes only; business logic lives in downstream presentation- layer backends.
all frontends (Web, iOS, Android, internal, partner)
│
▼
┌──────────────────────────────┐
│ Single UBFF GraphQL service │
│ (one schema, one deploy- │
│ ment artifact, one repo) │
└────────────────┬──────────────┘
▼
presentation-layer backends
(platform + domain specific logic)
│
▼
domain microservices
Why not Apollo Federation?¶
The explicit anti-pattern within this pattern. Apollo Federation is many services, one schema, composed at a router at runtime. The UBFF is one service, one schema, no runtime composition. The trade named in Zalando's 2021 post:
"instead of having multiple Graphs connected via a library and gateway we have a single service at Zalando which connects all the domains in a single schema Graph. This has tradeoffs which we have addressed as mentioned here, since we gain by keeping a single Graph in terms of tooling, deployment and governance."
The UBFF wins on: unified tooling, single deployment artifact, single governance surface. It loses on: per-domain deploy independence (all domains share the same release train) and per-domain runtime isolation (a bad resolver in domain X can degrade domain Y).
Canonical wiki instance: Zalando UBFF¶
Zalando's Unified Backend-For-Frontends GraphQL (Source: sources/2021-03-03-zalando-how-we-use-graphql-at-europes-largest-fashion-e-commerce-company):
- Production since end of 2018; development began H1 2018.
- 12+ domains in one monorepo under shared ownership.
- 150+ contributors (from 50 in 2020); 200+ consuming developers across 25-30 feature teams.
- >80% of Web and >50% of App use cases served.
- Runs on graphql-jit — Zalando's open-source JIT-compiled GraphQL executor.
- Uses an Entity system as first-class schema
citizens (
Product,Campaign, …), cross-linked into "a dense graph." - Deployed with per-platform bulkhead — separate deployments for Web and mobile Apps, same codebase.
How the monorepo-as-god-component risk is managed¶
The post names the concern: a 12+ domain monorepo is a God Component design smell. Two mitigations:
- Architectural: shared ownership across 12+ teams guided by a documented contribution framework; no single team can unilaterally reshape the graph.
- Operational: reliability patterns (Circuit Breakers, Timeouts, Retry) plus Bulkhead at the deployment level.
Adoption levers (from Zalando's retrospective)¶
Four levers scaled adoption 50 → 150+ contributors and 70 → 200 consumers in one calendar year:
- One-stop-shop Documentation (Divio framework) with embedded GraphiQL + Voyager + practice exercises.
- Dedicated support chat for users and contributors.
- Company-wide training (one session hit 150+ attendees).
- Schema-design consultation hours provided by the platform team for every new domain integrating into the graph.
Hard problems this pattern introduces¶
- Single-service deploys. No per-domain deploy independence — every team's changes ride the same release train.
- Single-service blast radius. A bad resolver in domain X can degrade latency or error rates for domain Y. Per-platform bulkhead only splits by Web/App, not by domain.
- Schema governance is load-bearing. Without a dedicated governance team and explicit contribution principles, the graph fractures.
- Scaling the execution engine. At Zalando's density
the reference
graphql-jsinterpreter was insufficient; they had to build and open-source graphql-jit. - The Entity system is hard to get right. Cross- domain first-class entity identity is a schema-design problem every organisation has to solve uniquely.
Contrast with adjacent patterns¶
- patterns/federated-graphql-subgraph-per-domain — same goal (unified graph), opposite topology (many services, one router).
- patterns/graphql-unified-api-platform — the broader umbrella; UBFF is the single-service implementation, federation is the distributed one.
- Per-surface BFF (what UBFF replaces) — one BFF service per surface (Web, iOS, Android, …); named in concepts/backend-for-frontend.
Seen in¶
- sources/2021-03-03-zalando-how-we-use-graphql-at-europes-largest-fashion-e-commerce-company — Zalando UBFF; first wiki instance.
Related¶
- systems/zalando-graphql-ubff — canonical instance
- systems/graphql
- systems/graphql-jit — the execution engine
- systems/apollo-federation — the explicit not-chosen alternative
- concepts/backend-for-frontend
- concepts/unified-graph-principled-graphql
- patterns/business-logic-free-data-aggregation-layer
- patterns/per-platform-deployment-bulkhead
- patterns/graphql-unified-api-platform
- patterns/federated-graphql-subgraph-per-domain