Skip to content
AB

SwiftData in an Offline-First Application

Use local persistence as a responsive product capability with explicit freshness, sync, and conflict rules.

Ashish BhakhandPublished

Offline-first is more than caching the last response. The local store supports real user work while the network is unavailable, and synchronization later reconciles that work.

SwiftData models need stable identities, update timestamps, ownership, and deletion representation where remote synchronization requires it.

Code
@Model
final class WorkoutDraft {
    @Attribute(.unique) var id: UUID
    var updatedAt: Date
    var syncStateRaw: String
    var deletedAt: Date?
}

Feature code should depend on a client, not ModelContext. That client can provide cached reads, local writes, and explicit refresh operations.

Define freshness honestly. A screen may show saved data immediately with a “last updated” state while refreshing. Empty local data and failed remote refresh should not be indistinguishable.

Deleting a synced record often requires a tombstone until the server acknowledges it. Physically removing it immediately can cause another device's old copy to return.

Conflict rules must be per domain. A user-edited title may use last-write-wins. Additive health events should deduplicate by semantic identity. Server-computed scores may always accept the newest algorithm version.

Test launches without network, local edits during a failed sync, repeated pulls, tombstone propagation, and reinstall recovery. SwiftData supplies persistence; offline-first behavior comes from the synchronization contract around it.

← Back to all writing