SYSTEM Cited by 2 sources
Zalando Unified Backend-For-Frontends (UBFF) GraphQL¶
What it is¶
Zalando's single-service unified GraphQL schema that acts as the Unified Backend-For-Frontends for every Web and mobile-App feature team across Europe's largest fashion e-commerce platform. Development began in H1 2018; it has been in production since end of 2018. By February 2021 it spans 12+ domains in a shared-ownership monorepo, serves >80% of Web and >50% of App use cases, and is consumed by 200+ developers across 25-30 feature teams (Source: sources/2021-03-03-zalando-how-we-use-graphql-at-europes-largest-fashion-e-commerce-company).
Architectural shape¶
Web clients iOS/Android App clients
│ │
▼ ▼
┌──────────────┐ ┌──────────────┐
│ UBFF GraphQL │ │ UBFF GraphQL │
│ (Web deploy) │ │ (App deploy) │ ← per-platform
└──────┬───────┘ └──────┬───────┘ bulkhead
│ │
└──────────┬────────────┘
▼
presentation-layer backends
(domain + platform-specific logic)
│
▼
domain backends
(Product, Campaign, …)
Two deployment shapes of the same codebase — one serving Web, one serving mobile Apps — implement the Bulkhead pattern. Behind the UBFF sits a presentation layer of domain/platform- specific backend services; the UBFF itself follows a strict No Business Logic principle and only aggregates and shapes.
Core design choices¶
- One graph, one service. Unlike Apollo Federation, there is no runtime composition of subgraphs. One GraphQL service, one schema, one deployment artifact (two deployment shapes for platform bulkheading). The post is explicit: "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."
- Entity system as first-class abstraction. Content and
domain models are exposed as named entities —
Product,Campaign, … — that cross-link into "a dense graph." The entity model is the schema's organising principle; the post flags it as the subject of its own future article (not detailed here). - JIT-compiled execution. Runs on
graphql-jit — an open-source JIT
GraphQL executor Zalando built and released as
zalando-incubator/graphql-jit. - Shared-ownership monorepo. One repository owned by 12+ domain teams under a documented contribution framework; contributor count grew 50 → 150+ in 2020.
- No business logic in the GraphQL layer. Enforced principle; domain/platform logic moves to presentation- layer backends behind the graph.
How they handle the "god component" risk¶
The post names the risk explicitly: a 12+ domain monorepo is a God Component architectural smell. Two mitigations:
- Architectural — shared ownership with an explicit contribution framework prevents any one team from unilaterally reshaping the graph.
- Operational — reliability patterns (Circuit Breakers, Timeouts, Retry) plus the Bulkhead pattern deployed as "separate deployments for Web and mobile Apps" — a Web regression cannot take the mobile app down and vice versa.
Adoption programme¶
Four levers the platform team used to scale adoption 50 → 150+ contributors and 70 → 200 consumers in 2020:
- One-stop-shop Documentation — single structured docs site (following Divio's documentation framework) with embedded GraphQL editor, schema documentation, Voyager for schema exploration, and practice exercises.
- Support chat — a dedicated channel for user and contributor queries.
- Trainings — company-wide GraphQL adoption training with 150+ participants.
- Consultation — platform team provides schema-design consultation hours for new domains ("GraphQL schema design is always a tricky topic even for frontend developers who can use GraphQL").
Positioning against peers¶
The post names and classifies five peer one-graph setups:
| Org | Shape | Note |
|---|---|---|
| Zalando (this) | Single service, unified schema | Chosen: unified tooling, single deployment, single governance point |
| GitHub | Single GraphQL API | Covers repos, users, marketplace |
| Shopify | Two unified graphs (StoreFront + Admin) | Split by audience (customers vs partners) |
| Airbnb | Working towards unified schema | Presented at GraphQL Summit 2019 |
| Expedia | REST → GraphQL central data graph | Motivated by "developers spending more time figuring out which service to call than shipping features" |
| Apollo Federation | Library + gateway across N subgraphs | Explicit not-chosen alternative |
| Netflix | One-graph in Studio ecosystem | Named peer |
Operational numbers (2021-02 snapshot)¶
| Dimension | Value |
|---|---|
| First production deploy | End of 2018 |
| Domains in the graph | 12+ |
| Contributors to monorepo | 150+ (from 50 in 2020) |
| Consuming developers | 200+ (from 70 in 2020) |
| Feature teams served | 25-30 |
| Web use cases served | >80% |
| App use cases served | >50% |
| Platform-specific deployments | 2 (Web + App) |
| Adoption training attendance | 150+ |
Gaps in the public record¶
- Schema size (type / field / resolver count) — undisclosed.
- Latency SLOs, QPS, p99 — undisclosed.
- Resolver fan-out / depth limits — undisclosed.
graphql-jitperformance delta vs reference executor — undisclosed.- Entity system internals — deferred to future post.
- Presentation-layer backend topology — described as "the presentation layer" with no further detail on per-domain or per-platform service topology.
- Schema evolution / deprecation tooling — undisclosed.
Error modeling discipline (2021-04 follow-up)¶
A companion post, Modeling Errors in GraphQL (2021-04-12), establishes the UBFF's discipline for error payloads. The core rule is a two-channel split by who can act on the failure — see concepts/error-action-taker-classification:
- Developer-actionable (front-end code acts on it — 404,
authZ, internal errors) → stay in
response.errorswith a parseableextensions.code. See patterns/error-extensions-code-for-developer-actionable-errors. - Customer-actionable (only the end user can fix it —
canonically mutation input validation) → modelled in the
schema as a Problem type on a
union ...Result = Success | Problem. Named after RFC 7807 to avoid colliding with GraphQL's reservederror. See patterns/problem-type-for-customer-actionable-errors and the Result union pattern.
The UBFF team is explicit that overusing schema Problem
types — making every field a Success | Error union —
destroys GraphQL's query-shape ergonomics, so Problem types
are restricted to mutation inputs (Source:
sources/2021-04-12-zalando-modeling-errors-in-graphql).
Seen in¶
- sources/2021-03-03-zalando-how-we-use-graphql-at-europes-largest-fashion-e-commerce-company — first wiki source on Zalando's UBFF; Part 1 of a planned series on UBFF.
- sources/2021-04-12-zalando-modeling-errors-in-graphql — the error-modeling installment of the same series.
Related¶
- systems/graphql — the query language substrate
- systems/graphql-jit — the JIT execution engine Zalando built for the UBFF
- systems/apollo-federation — the explicit not-chosen alternative
- systems/netflix-enterprise-graphql-gateway — peer one-graph architecture
- systems/rfc-7807-problem-details — the naming source for schema-level Problem types
- patterns/unified-graphql-backend-for-frontend — canonical instance
- patterns/business-logic-free-data-aggregation-layer
- patterns/per-platform-deployment-bulkhead
- patterns/result-union-type-for-mutation-outcome — mutation error shape
- patterns/problem-type-for-customer-actionable-errors
- patterns/error-extensions-code-for-developer-actionable-errors
- concepts/backend-for-frontend — the pattern this replaced
- concepts/unified-graph-principled-graphql
- concepts/problem-vs-error-distinction
- concepts/error-action-taker-classification
- companies/zalando