SYSTEM Cited by 1 source
Zalando Appcraft¶
What it is¶
Appcraft is Zalando's server-driven mobile UI framework — the runtime the Zalando iOS + Android apps use to render dynamic content pages whose structure, content, and behaviour are defined per-request by the server rather than baked into the app binary. Design started in 2018 as the replacement for the 2016-era Truly Native Apps (TNA) framework; by 2024 it serves 13 dynamic pages in the Zalando app including the newly-shipped Zalando Stories feature (Source: sources/2024-05-15-zalando-transitioning-to-appcraft-evolution-of-zalandos-server-driven-ui-framework).
Appcraft is SDUI of the Airbnb-Ghost-Platform / Yelp CHAOS lineage: the server emits a JSON screen-configuration tree, the client renders it via a bundled set of primitives. What is distinctive about Appcraft:
- It is mobile-native, not React-based — the client is wired straight into each platform's native UI substrate.
- It adopts the Elm architecture (Model/View/Update) as the mobile-side programming model.
- Layout is Flex on top of Texture (iOS) and Litho (Android), both of which sit on top of UIKit / the Android View system rather than replacing them — see patterns/flex-on-top-of-native-ui-framework.
- Schema versioning lives entirely server-side — see concepts/server-owned-schema-versioning.
Architecture at a glance¶
┌─────────────────────────────────────────────────────┐
│ Zalando iOS / Android app │
│ │
│ ┌──────────────────────────────────────────────┐ │
│ │ Appcraft client │ │
│ │ - Primitives (Label, Button, Image, │ │
│ │ Video, Layout) bundled in binary │ │
│ │ - Elm runtime (Model/View/Update) │ │
│ │ - Flex → native-tree transform │ │
│ │ (iOS: Texture / Android: Litho) │ │
│ │ - Action dispatcher (tap, track, navigate) │ │
│ │ - Deep-link resolver (via middleware) │ │
│ └──────────────────────────────────────────────┘ │
└──────────────┬──────────────────────────────────────┘
│ fetch screen JSON
▼
┌─────────────────────────────────────────────────────┐
│ Appcraft backend (micro-frontends part-2 system) │
│ - Screen-config authoring │
│ - Per-platform / per-app-version / A/B gating │
│ - Component-version backward-compat logic │
│ - Route configuration for new screens │
└─────────────────────────────────────────────────────┘
The deep-link-to-screen resolution runs:
deep-link → middleware → API endpoint → screen JSON
(client requests, client doesn't know the API shape)
See concepts/deep-link-to-screen-config-resolution and patterns/deep-link-indirection-middleware.
Component schema¶
A component in Appcraft is a typed tree node:
{
"type": "layout",
"id": "root-container-layout-id",
"flex": {},
"props": {},
"children": [
{
"type": "image",
"id": "id1",
"flex": {},
"props": {},
"events": {
"tap": [
{"id": "id2", "props": {}, "type": "track"},
{"id": "id3", "props": {}, "type": "navigate"}
]
}
}
],
"events": {}
}
(Source: sources/2024-05-15-zalando-transitioning-to-appcraft-evolution-of-zalandos-server-driven-ui-framework, verbatim from the post.)
Every node carries flex (layout) + props (primitive-
specific) + events (ordered action lists). The event
vocabulary includes explicit interactions (tap,
long-press) and implicit lifecycle events (scroll-forward,
dismiss). Actions are the extension point: each action
type (track, navigate, …) is implemented on the client.
Primitives (the bundled-in-binary vocabulary)¶
Five named in the post: Label, Button, Image,
Video, Layout container (the universal composition
node). Canonicalised as
concepts/ui-primitives-as-platform-building-blocks.
Extension to the set requires a client release — e.g. the post mentions Composite Label (sub-text styling / variable font sizes / decoration) was added later because a plain Label couldn't render prices correctly. See concepts/client-release-needed-only-for-new-primitives.
What's on the server, what's on the client¶
Server (deployed same-day):
- Screen definitions (component trees).
- Route configuration (deep-link → API mapping).
- Component-version policy — per-app-version / per-platform / A/B / premise gating.
- Backward-compat logic (minimum-app-version per component).
- Tracking schema (event names, parameters).
Client (requires App Store release):
- Primitive implementations.
- Action handlers (
navigate,track, …). - Flex → Texture/Litho layout transform.
- Elm runtime.
- Deep-link resolver client half (but not the route table).
The explicit rule, verbatim from the post: "A client-release is only required when there's a need to introduce a new primitive or extend the contract of an existing one to support additional behaviour."
Testing surfaces¶
Two, deliberately:
- Appcraft Browser — a standalone demo app with a URL address bar. Any endpoint emitting Appcraft screen JSON (including localhost) can be pasted in; the screen renders in an isolated environment with minimal dependencies. Used by web developers (who author screens) to iterate on the renderer logic without building the full Zalando app. Canonicalised as patterns/demo-harness-for-sdui-rendering.
- PR-deployed renderer pinning — renderer changes are deployed to staging from a PR; the PR number is entered into the debug build of the real Zalando app, which then exercises the PR's renderer against the full app environment. Canonicalised as patterns/pr-deployed-renderer-testing-in-debug-app.
Business impact (2024, per post)¶
- 13 dynamic pages including Zalando Stories.
- Two tracking-SDK migrations (2021, 2024) with no per-Appcraft-screen mobile work.
- Multiple app redesigns — notably reduced mobile engineering effort on Appcraft-served pages.
- Fast-prototyping substrate — engineers + designers iterate on new UI designs within a week.
- Reduced MTTR — server-side component disable removes need for hotfix releases.
- Cyber Week battle-tested — performs under Zalando's peak sales load.
Backend companion¶
The backend serving Appcraft screen JSON is the subject of Zalando's [2021-09 micro-frontends part-2 post] (https://engineering.zalando.com/posts/2021/09/micro-frontends-part2.html), which the Appcraft post explicitly references: "Appcraft has been serving as a stalwart in the realm of backend driven screen frameworks. Read all about the backend system that empowers this platform." That post covers the Rendering Engine architecture — Node.js + custom React reconciler — where the native-apps reconciler path emits JSON instead of HTML. Appcraft is the client-side consumer of that JSON on mobile; the Rendering Engine is the server-side producer.
Contrast with other Zalando UI platforms¶
- vs Interface Framework (IF) — IF is the web-native second-gen frontend platform (React + TypeScript + entity tree); IF + Appcraft together form Zalando's two-surface SDUI-ish frontend story (web via React renderers, mobile via primitives + Flex + Elm).
- vs the custom-React-reconciler for Native Apps path — the 2021-09 micro-frontends part-2 post documents a "Custom React reconciler that emits app-compatible JSON" (see patterns/same-react-code-web-and-native-via-reconciler). Appcraft is the counterpart on the client: it consumes such JSON. The reconciler is one valid JSON-emission path on the server; Appcraft is agnostic to whether the server-side authoring is React-based or not.
- vs React Native path — Zalando's 2025-10 mobile-RN post describes a newer, parallel cross-platform strategy using React Native for screens that need richer interactivity; Appcraft continues to serve its 13 dynamic-content pages. The two coexist as of 2025.
Comparison with other SDUI systems on-wiki¶
| Property | Appcraft | Yelp CHAOS |
|---|---|---|
| Surface | Mobile-native only | Web + iOS + Android + Python |
| UI substrate | Texture / Litho | Native RN + web DOM |
| Layout language | Flex on native UI framework | Platform-specific |
| Cross-platform codegen | None (shared Flex spec) | Konbini |
| Schema version control | Server-only | Client bundles spec version |
| Client-release trigger | New primitive / new action | New component / breaking change |
| Backend-to-client wire | JSON screen tree | GraphQL + JSON-string params |
Open challenges (named in post)¶
- Monitoring gaps — dynamic screens sometimes see issues reach the platform team only after user-visible impact.
- Generality-vs-restrictiveness trade-off when adding new primitive features.
- Interoperability — non-Appcraft components inside Appcraft screens (and vice-versa); worked example: Home Screen's tabular structure where each tab is an Appcraft screen embedded in a non-Appcraft host.
- Third-party UI library drift — Texture and Litho behaviour varies across OS versions.
- Ownership fuzziness — web developers authoring app screens blurs the mobile-vs-web team boundary.
Seen in¶
- sources/2024-05-15-zalando-transitioning-to-appcraft-evolution-of-zalandos-server-driven-ui-framework — canonical source. 6-year retrospective covering TNA→Appcraft motivation, Elm + Flex + primitives design, server-owned schema versioning, deep-link indirection, two testing surfaces, 2024 business impact, open challenges.
Related¶
- systems/zalando-truly-native-apps-tna
- systems/zalando-appcraft-browser
- systems/texture-asyncdisplaykit
- systems/litho
- systems/zalando-interface-framework
- systems/zalando-rendering-engine
- systems/yelp-chaos
- concepts/server-driven-ui
- concepts/elm-architecture
- concepts/flexbox-as-cross-platform-layout-primitive
- concepts/ui-primitives-as-platform-building-blocks
- concepts/deep-link-to-screen-config-resolution
- concepts/server-owned-schema-versioning
- concepts/client-release-needed-only-for-new-primitives
- concepts/same-day-ui-delivery
- concepts/appcraft-interoperability
- patterns/flex-on-top-of-native-ui-framework
- patterns/deep-link-indirection-middleware
- patterns/demo-harness-for-sdui-rendering
- patterns/pr-deployed-renderer-testing-in-debug-app
- companies/zalando