BFF vs SDUI: Before You Build an SDUI Engine, Make Sure You Don’t Just Need a BFF
You’ve probably heard both of these terms in app-building talks: Backend for Frontend (BFF) and Server-Driven UI (SDUI). They sound alike…
BFF vs SDUI: Before You Build an SDUI Engine, Make Sure You Don’t Just Need a BFF
You’ve probably heard both of these terms in app-building talks: Backend for Frontend (BFF) and Server-Driven UI (SDUI). They sound alike, they both move work to the server and they are often used together. That’s why people mix them up.

But they fix different problems and they work at different levels. If you mix them up, you can build too much (a big SDUI engine when you only needed a BFF) or too little (a BFF when your real pain is updating screens). This article explains each one in simple words, shows the difference and helps you choose.
The Short Answer
A BFF controls the data your app gets. SDUI controls the screens your app shows.
That is really the whole idea. Here is what it means:
- With a BFF, your app still builds its own screens. It knows what a product card looks like and where things go. The server just sends it clean, ready-to-use data.
- With SDUI, the server builds the screens. It tells the app which parts to show, in what order and with what text and images. The app just follows the instructions and draws them.
So they work at two different levels. That is why you can use both at the same time. They help each other, they do not fight.
What is a Backend for Frontend (BFF)?
A BFF is a small backend made for one type of app. The idea was made popular by Sam Newman. Instead of your app talking to many small services directly, it talks to one helper backend built just for it.
iOS App ──► iOS BFF ──┐
Android App ──► Android BFF ──┼──► [ User service, Catalog service, Pricing service, ... ]
Web App ──► Web BFF ──┘
The BFF’s job is to collect, clean up and shape data for that one app:
- Combine data (Aggregation): It calls five services and sends back one neat answer. So your phone makes one request instead of five over a weak mobile signal.
- Send less (Payload Optimization): It removes data the phone does not need. Smaller answers mean less battery and less internet use.
- Reshape data (Model Mapping): It turns messy backend data into the exact clean shape your app wants.
- Hide the mess (Encapsulation): It hides the hard backend parts, the changes and the version updates from your app.
Important: A BFF does not decide how the screen looks. It only sends data. The app is still fully in charge of the look.
What a BFF is good for
- Too many calls or too much data: Your app makes too many requests or downloads big, heavy answers.
- Different apps need different data: Your watch, your phone and your website each need a different part of the same data.
- Hide your services: Your app should not know how your backend is split into services.
- Team freedom: The app team can build, ship and change their own BFF without waiting for the backend team.
What a BFF costs you
A BFF is not free. Watch out for these problems:
- Doing the same work many times (Logic Duplication): The iOS, Android and Web BFFs often write the same logic three times. This is the most common BFF trap. It is also the main reason some teams use one shared gateway instead.
- It gets too big (the Fat BFF): People put extra logic into the BFF because it is easy. Over time it becomes a big mess a hidden monolith.
- One more thing to run: Each BFF is another service to ship, watch and fix. It also adds one more network step, which adds a little delay.
- Who owns it? Is the BFF a frontend job or a backend job? Teams argue about this and forgotten BFFs go bad over time.
Is a BFF just GraphQL?
Many people ask this. Not exactly. GraphQL is one way to build what a BFF does. Instead of building a special endpoint for each app, the app asks for the exact fields it wants in one query. A shared GraphQL gateway (called federated GraphQL) acts like one BFF for all apps. It solves the same problem (the right data, fewer calls) but with a different tool and it has its own hard parts, like caching and controlling heavy queries.
What is Server-Driven UI (SDUI)?
SDUI goes one step further. The server does not just send data. It also sends the layout of the screen: which parts to show, how they are ordered and what is inside them.
The server sends a description (usually JSON) and the app reads it and draws ready-made native parts.
{
"screen": "home",
"components": [
{ "type": "hero_banner", "image": "...", "title": "Summer Sale" },
{ "type": "product_carousel", "title": "For You", "items": [ ... ] },
{ "type": "spacer", "height": 16 },
{ "type": "promo_card", "cta": "Shop now", "action": "open_route", "url": "app://sale" }
]
}
The app does not hard-code this screen. It keeps a list of parts it already knows (hero_banner, product_carousel and so on) and builds whatever the server sends. Change the server's answer and the screen changes right away with no app store update needed.
Who uses it
Big apps use SDUI for screens that change a lot like home feeds, search results, sales pages and even checkout. Examples:
- Airbnb (their well-known system is called Ghost Platform)
- Lyft
- DoorDash
- Spotify
What SDUI is good for
- No waiting for app store updates: Change a screen in hours, by updating the server. You skip the slow app store review and you do not wait weeks for users to update.
- Easy testing (Experimentation): Try different layouts orders and content for different users all from the server, in real time.
- Same look everywhere: One server answer drives iOS, Android and Web in the same way. No drifting apart.
- Help old apps: You can safely update a screen even for users who have not updated their app in months.
The Costs of SDUI (The Hard Truth)
SDUI sounds like a magic fix, but it brings a lot of hard work. Using it too early is a common and expensive mistake.
1. Buttons need to do things (the Action problem)
Drawing a button from JSON is easy. Saying what the button does is the hard part. A real SDUI system needs a plan for actions, sometimes called a Server-Driven Actions (SDA) system.
- Map names to handlers (Command Pattern): The server sends an action name as text (like open page or show fingerprint screen). The app must match each name to the right code that runs it.
- Keep state in sync: If a user taps a Favorite button inside an SDUI part, the app must update that state and keep it in sync with the normal (non-SDUI) parts of the app. This requires a centralized state architecture (like an event bus or shared global repositories) so that local interactions safely broadcast across the native stack.
2. Safety and trust
This is the cost most people forget. When the server tells the app what to do, the app is running the server’s orders. That opens a door, so be careful:
- Allow only known actions. The app must run only a fixed, known list of actions. Never run just any text the server sends.
- Check every link. A link from the server can be dangerous if you open it without checking first.
- Protect sensitive features. Never let a general server action trigger payments, fingerprints or file access without a fixed, hard-coded check in the app.
3. Old apps don’t know new parts (Schema Evolution)
Apps live on phones for a long time. If app version 1.0 gets a story_carousel part that was added in version 1.5, it has no idea how to draw it.
- Don’t crash (Graceful Degradation): If the app gets a part it does not know, it must skip it safely or show empty space not crash.
- Tell the server what you support (Capabilities Handshake): The app sends its version or a list of parts it supports, in the request. The server then builds a screen using only the parts that this app version can safely show.
4. It can be slower (Performance Overhead)
A built-in native screen is compiled, optimized and fast. An SDUI screen is evaluated at runtime, which costs precious system resources:
- Bigger payloads: A structural layout (components, properties, deep nesting, actions) is inherently heavier over the wire than plain business models.
- Runtime parsing & layout engine penalties: Reading large JSON trees and mapping them to native constructors dynamically places an extra computing burden on the device’s thread pool, which can lead to micro-stutters if not carefully throttled within the 16ms rendering frame.
- Caching limits: While you can split and cache layout schemas at the CDN edge while loading raw dynamic data separately, the processing cost of composing the UI tree never completely drops to zero.
5. Bugs are harder to find (Tooling)
Because screens come from data, normal debugging tools do not help much. Bugs become data problems. To copy a bug, you often must capture the exact JSON that user got at that exact moment including which test group they were in.
Side-by-Side Comparison
DimensionBackend for Frontend (BFF)Server-Driven UI (SDUI)Who is in control?App controls the look, server controls the data shape.Server controls the layout and the parts.What level does it work at?The data / API level.The screen / look level.What is sent over the network?Clean data models.A description of the screen: parts, styles and actions.What does the app do?Builds the screens itself, knows the flow.Just draws what the server sends.Caching BoundaryNormal web caching, based on data freshness contracts.Layouts cache very well, data can be loaded separately.Testing ComplexityStandard. Contract tests (like Pact).Hard. Needs component screenshot tests and layout validations.Impact on App SizeMinimal. Uses normal business data definitions.High. Requires writing or bringing in a heavy UI interpretation engine.Main winFewer calls, smaller data, clean contracts.Change the UI anytime, test fast on the server.
They Are Not Rivals They Are a Stack
Here is the key point most BFF vs SDUI talks miss: SDUI almost always needs a BFF behind it.
Something on the server has to gather the data, choose which parts to show this user, run the tests and build the final screen. That something is a BFF.
[ Mobile / Web App ] (just draws the screen)
│
│ (screen description in JSON)
▼
┌───────────────────────────────────────────┐
│ BFF Layer │
│ ─ Gathers data from the services │
│ ─ Runs A/B tests and personalization │
│ ─ Builds the final screen description │
└─────────────────────┬─────────────────────┘
│
┌───────────┼───────────┐
▼ ▼ ▼
[Catalog Svc] [User Svc] [Promo Svc]
So the real question is not BFF or SDUI? It is: How much should the server control?
From app controls everything to server controls everything
[1] App builds [2] BFF cleans [3] Server picks [4] Server picks [5] Server builds
everything ► the data ► what's in ► the order of ► the whole screen,
(screens & API) (app owns layout) the list the parts styles, & actions
Most strong teams sit between step 2 and step 4. Jumping straight to step 5 for the whole app is almost always the wrong move.
When to Use Which: A Simple Guide
Use a BFF when:
- You have many kinds of apps (iOS, Android, Web, smart devices) that truly need different data.
- Your backend has too many small services for the app to call directly.
- You want the app team to build and ship their own backend layer on their own.
- You are happy to let the app fully control the look and the flow.
Use SDUI when:
- Waiting for app store updates clearly slows your business down.
- You want to test different layouts and content often and control them from the server.
- You have screens that change a lot and are built from reusable parts (home feeds, search results, sales pages).
- You are big enough that the extra work (building the reader, the handshake, the safe fallbacks) clearly pays off.
Avoid (or limit) SDUI when:
- Your screens are very interactive lots of gestures, animations or use of the camera, photo editors or complex forms. These do not fit the just draw what the server says model.
- Your app is small or its main screens rarely change. You would build a big engine you do not need.
A Simple Plan: The Hybrid Way
You almost never need to make the whole app server-driven. The most practical pattern is a clear split:
- Build inside the app: the stable, very interactive, speed-sensitive screens (checkout, settings, login, photo or media editors).
- Drive from the server: the screens that change a lot (home tabs, onboarding, banners, sales and seasonal pages).
- Put a BFF in front of both so the data stays clean and simple for everyone.
Conclusion
You almost never need to make the whole app server-driven. The most practical pattern is a clear split:
- Build inside the app: the stable, very interactive, speed-sensitive screens (checkout, settings, login, photo or media editors).
- Drive from the server: the screens that change a lot (home tabs, onboarding, banners, sales and seasonal pages).
- Put a BFF in front of both so the data stays clean and simple for everyone.
Do not pick a pattern just because it is popular. Start with a BFF. Add server-driven content where it helps. Build a full SDUI engine only for the few important screens where the reward is clearly worth the extra work.
Going Deeper: The Blueprint & The Execution
If you want to transition from theory to real-world engineering, I’ve broken down the exact steps, code structures and trade-offs in these dedicated deep dives:
- For the Systems Architect: If you are designing the system and need an enterprise-grade blueprint, check out Server-Driven UI Architecture: Approaches, Trade-offs and the Honest Costs. We look closely at engineering realities, schema contracts, and systemic risks.
- For the Flutter & Dart Engineer: If you are ready to write code and want to see how to implement this end-to-end, read A Definitive Guide to Flutter SDUI: Architecting Zero-Update Interfaces Beyond the App Store. This article walks through building a dynamic rendering pipeline using Flutter and Dart Frog on the backend.
메타데이터
- post_id
- 31503b1e4ced
- slug
- bff-vs-sdui-before-you-build-an-sdui-engine-make-sure-you-dont-just-need-a-bff-31503b1e4ced
- url
- https://medium.com/@abied.abiad/bff-vs-sdui-before-you-build-an-sdui-engine-make-sure-you-dont-just-need-a-bff-31503b1e4ced
- canonical_url
- https://medium.com/@abied.abiad/bff-vs-sdui-before-you-build-an-sdui-engine-make-sure-you-dont-just-need-a-bff-31503b1e4ced
- author_url
- https://medium.com/@abied.abiad
- status
- ok
- fetched_at
- 2026-06-21 09:28:28