Mobile Development 17 min read

Airbnb’s Journey from Epoxy/UIKit to SwiftUI: Evaluation, Migration, and Lessons Learned

Airbnb’s three‑stage migration from its custom Epoxy/UIKit stack to SwiftUI involved extensive evaluation, rebuilding the design system with flexible style protocols, bridging UIKit and SwiftUI, adopting one‑way data flow, extensive testing and training, resulting in six‑fold code reduction, comparable performance, widespread production adoption, and higher developer productivity despite remaining framework challenges.

Airbnb Technology Team
Airbnb Technology Team
Airbnb Technology Team
Airbnb’s Journey from Epoxy/UIKit to SwiftUI: Evaluation, Migration, and Lessons Learned

Introduction: This article describes Airbnb’s practice of adopting SwiftUI in its iOS app and replacing the legacy UI framework (Epoxy built on UIKit) with SwiftUI.

Choosing the right UI framework is crucial for both user experience and developer productivity. A well‑designed declarative UI framework can make the app feel smooth and enable engineers to express ideas efficiently, while a poorly designed API adds complexity and slows development.

Airbnb built its own declarative UI framework, Epoxy, in 2016 on top of UIKit. With the release of SwiftUI in 2019, Airbnb evaluated it for three years and began migration in 2022 when SwiftUI’s stability and API coverage improved.

Evaluation and Planning Using SwiftUI

Airbnb hypothesized that SwiftUI would not degrade user experience and would improve developer experience because:

Flexibility and composability through generic views and modifiers.

Fully declarative code that is easier to understand and maintain.

Less code, leading to fewer bugs.

Faster iteration via Xcode previews.

Lower cognitive load for new engineers.

The migration was planned in three stages:

Stage 1 – Build reusable leaf view components.

Stage 2 – Build complete pages (e.g., booking detail, user profile).

Stage 3 – Build full features composed of multiple pages.

By the time of writing, stages 1 and 2 were completed; stage 3 awaits more flexible navigation APIs in SwiftUI.

Adopting SwiftUI in the Design System

Airbnb rebuilt its design system for SwiftUI, introducing a flexible style protocol. Example protocol definition:

public protocol FlexibleSwiftUIViewStyle: DynamicProperty {
/// The content view type of this style, passed to `body()`.
associatedtype Content
/// The type of view representing the body.
associatedtype Body: View
/// Renders a view for this style.
@ViewBuilder
func body(content: Content) -> Body
}

A concrete implementation for a numeric stepper:

public struct DefaultStepperStyle: DLSNumericStepperStyle {
public var valueLabel = TextStyle…
public func body(content: DLSNumericStepperStyleContent) -> some View {
HStack {
Button(action: content.onDecrement) { subtractIcon }
.disabled(content.atLowerBound)
Text(content.description)
.textStyle(valueLabel)
Button(action: content.onIncrement) { addIcon }
.disabled(content.atUpperBound)
}
}
}

Using the style is as simple as:

DLSNumericStepper(value: $value, in: 0..)
.dlsNumericStepperStyle(CustomStepperStyle())

Bridging Epoxy and SwiftUI

Airbnb created infrastructure to embed SwiftUI views inside Epoxy’s UIKit lists and vice‑versa. Example of a SwiftUI row embedded in Epoxy:

SwiftUIRow(
title: "Row \(id)",
subtitle: "Subtitle")
.itemModel(dataID: id)

And a UIKit view exposed as a SwiftUI view:

EpoxyRow.swiftUIView(
content: .init(title: "Row \(index)", subtitle: …),
style: .small)
.configure { context in
print("Configuring \(context.view)")
}
.onTapGesture {
print("Row \(index) tapped!")
}

One‑Way Data Flow

Airbnb leveraged a one‑way data flow pattern in Epoxy and extended it to SwiftUI by making the StateStore conform to ObservableObject. Example counter implementation in Epoxy/UIKit:

// In Epoxy/UIKit:
struct CounterContentPresenter: StateStoreContentPresenter {
let store: StateStore
var content: UniListViewControllerContent {
.currentDLSStandardStyle()
.items {
BasicRow.itemModel(
dataID: ItemID.count,
content: .init(titleText: "Count \(state.count)"),
style: .standard)
.didSelect { _ in
store.handle(.increment)
}
}
}
}

And the equivalent SwiftUI version:

// In SwiftUI
struct CounterScreen: View {
@ObservedObject let store: StateStore
var body: some View {
DLSListScreen {
DLSRow(title: "Count \(store.state.count)")
.highlightEffectButton {
store.handle(.increment)
}
}
}
}

Testing

SwiftUI components are made testable via snapshot testing and ViewInspector. Example of a view definition for snapshot tests:

enum DLSPrimaryButton_Definition: ViewDefinition, PreviewProvider {
static var contentVariants: ContentVariants {
DLSPrimaryButton(title: "Title") { … }
.named("Short text")
DLSPrimaryButton(title: "Title") { … }
.disabled(true)
.named("Disabled")
}
}

Training

Airbnb ran multiple half‑week SwiftUI workshops. Attendance was ~50 % of iOS engineers. Post‑workshop surveys showed a 37 % increase in confidence with SwiftUI basics and a 39 % increase for building new components. One‑year‑later participants retained an 8 % higher expertise level compared to non‑participants.

Key Findings

Code reduction: a comment‑card UI went from 1 121 lines (UIKit/Epoxy) to 174 lines (SwiftUI), a 6× reduction.

Performance: UI performance scores are comparable to UIKit; a reusable UIHostingController pool mitigates the small overhead of UIHostingController instantiation.

Adoption: By September 2023, >500 SwiftUI views and ~200 full pages were in production, many shipped in the 2023 summer release.

Challenges

Airbnb still faces challenges such as the closed‑source nature of SwiftUI, limited visibility into future roadmap, backward compatibility for older iOS versions, lack of custom transition APIs, issues with LazyVStack/ScrollView (animations, pre‑loading, state reset), incomplete text‑input APIs, and numerous bug reports submitted to Apple.

Conclusion

Despite challenges, Airbnb’s careful migration to SwiftUI—rebuilding the design system, investing in training, and providing seamless integration with existing frameworks—has improved development speed, developer satisfaction, and maintained high quality. The team looks forward to continued evolution of SwiftUI and its broader adoption in Airbnb’s products.

mobile developmentiOSSwiftUIui-frameworkDeclarative UIAirbnbEpoxy
Airbnb Technology Team
Written by

Airbnb Technology Team

Official account of the Airbnb Technology Team, sharing Airbnb's tech innovations and real-world implementations, building a world where home is everywhere through technology.

0 followers
Reader feedback

How this landed with the community

login Sign in to like

Rate this article

Was this worth your time?

Sign in to rate
Discussion

0 Comments

Thoughtful readers leave field notes, pushback, and hard-won operational detail here.