← All release notes
SwiftDataiOS 26Aug 21, 2026 · 5 min read

What's New in SwiftData — iOS 26

iOS 26 shipped one substantial SwiftData feature — model inheritance — and this covers what changed and how to migrate to it.

iOS 18 was the big swing: #Index, #Unique, custom DataStore backends, the history API. iOS 26 is quiet.

One substantial addition. Class inheritance for @Model types, plus the schema migration machinery to adopt it safely. No CloudKit sharing options. No dynamic predicates. Not this cycle.

#Model inheritance

Before iOS 26, every @Model type stood alone. No subclassing. That restriction is gone, so a base class can now be subclassed by other @Model classes. The obvious fit is a natural hierarchy: a Trip base with BusinessTrip and PersonalTrip variants that each add their own fields.

@Model
class Trip {
    var name: String
    var destination: String
    var startDate: Date
    var endDate: Date

    init(name: String, destination: String, startDate: Date, endDate: Date) {
        self.name = name
        self.destination = destination
        self.startDate = startDate
        self.endDate = endDate
    }
}

@available(iOS 26, *)
@Model
final class BusinessTrip: Trip {
    var costCenter: String

    init(name: String, destination: String, startDate: Date, endDate: Date, costCenter: String) {
        self.costCenter = costCenter
        super.init(name: name, destination: destination, startDate: startDate, endDate: endDate)
    }
}

Reach for it when two or more models genuinely share fields and behavior and the alternative is duplicating name, destination, startDate and endDate across both. The other option is hiding that duplication behind a shared protocol that still duplicates the storage.

#Fetching and querying across a hierarchy

Fetch the base type and SwiftData hands back instances of whatever subclass each row actually is. A single FetchDescriptor<Trip> gives you polymorphic results, not flattened base-class data.

Filtering is narrower. #Predicate still runs against the base type's shared properties, so to filter on costCenter you fetch or query BusinessTrip specifically. If your app already treats trips generically and only occasionally needs the business-specific fields, this beats bolting optional properties onto one flat class.

#Migrating an existing schema to inheritance

Adding a subclass to a model you already ship is a schema change. It goes through the same VersionedSchema / MigrationStage / SchemaMigrationPlan machinery SwiftData has used since iOS 17. Nothing new, but you will have to touch it. Add the subclass to your latest schema version's model list, then add a migration stage from the previous version:

enum SchemaV1: VersionedSchema {
    static var versionIdentifier = Schema.Version(1, 0, 0)
    static var models: [any PersistentModel.Type] { [Trip.self] }
}

enum SchemaV2: VersionedSchema {
    static var versionIdentifier = Schema.Version(2, 0, 0)
    static var models: [any PersistentModel.Type] { [Trip.self, BusinessTrip.self] }
}

enum TripMigrationPlan: SchemaMigrationPlan {
    static var schemas: [any VersionedSchema.Type] { [SchemaV1.self, SchemaV2.self] }
    static var stages: [MigrationStage] {
        [.lightweight(fromVersion: SchemaV1.self, toVersion: SchemaV2.self)]
    }
}

A lightweight stage covers you when you're only adding a new subclass and no existing rows need reshaping. Reclassifying existing Trip rows into BusinessTrip? That's .custom.

#Availability and deployment target reality

Inheritance is gated to iOS 26 and later. The subclass declarations need @available(iOS 26, *), and so does every code path that constructs or fetches them.

Still supporting iOS 17 through 25? Then you maintain two shapes of the model, conceptually, until you can drop the older targets. There's no fallback that lets an older OS gracefully see only the base type.

#What didn't change this year

Worth saying plainly, because a lot of writeups blur consecutive releases together: #Index, #Unique, the custom DataStore protocol, and ModelContext.fetchHistory all shipped in iOS 18. Not iOS 26. If you already target iOS 18+, you had those the whole time. Don't credit iOS 26 for work you can ship today.

#What to adopt first

  • No natural class hierarchy in your models today? Nothing here to adopt. Skip the release.
  • Have one, and your minimum deployment target is already iOS 26? Use inheritance to kill the duplicated properties across near-identical models.
  • Mixed deployment target: write the migration plan now, gate the subclass types behind @available, and ship the base-only schema to older OS versions until you can raise the floor.
  • Don't chase "new" SwiftData features that are iOS 18 holdovers. #Index and #Unique earn their keep regardless. Don't expect this release to have added to them.