SwiftData Indexes

When Apple launched SwiftData in iOS 17 it was missing the ability to add indexes. Apple corrected that omission in iOS 18.

Core Data Fetch Index

Core Data has long supported adding a fetch index to a property for faster database lookups. For example, if you fetch and sort items by a timestamp you might want to index the timestamp property.

In the Xcode Core Data Model Editor select the entity and then from the Editor use Add Fetch Index. Choose a suitable name for the index, change the property field to the name of the property you want to index and decide if you want ascending or descending order:

Adding a timestamp index to the Item entity

When Apple shipped SwiftData with Xcode 15 and iOS 17 it did not support database indexes. Apart from the performance impact it was also a concern if you wanted to use your Core Data schema with SwiftData:

Xcode File Inspector with Core Data Model option used with SwiftData ticked

In Xcode 15, if you tick the “Used with SwiftData” option in the file inspector Xcode gives you a warning:

Fetch indexes are not supported in SwiftData

That was true in iOS 17 but is no longer true with iOS 18. Unfortunately, Xcode 16 continues to show the same warning. I don’t know if there’s still some incompatibility or if that’s a bug (FB14485495).

Adding SwiftData Fetch Indexes (iOS 18)

First the bad news, this is an iOS 18 feature that does not back deploy to iOS 17. Here’s my SwiftData model for an Item taken from the Xcode project template:

@Model final class Item {
  var name: String
  var timestamp: Date

  init(name: String, timestamp: Date) {
    self.name = name
    self.timestamp = timestamp
  }
}

Use the #Index macro to specify the key path for each index you want to add:

@Model final class Item {
  // Add indexes for name and timestamp
  #Index<Item>([\.name], [\.timestamp])
  ...
}

You can only use the #Index macro once for each model class so you need to list all the indexes you want in the single macro. Note the subtle difference between adding an index for the individual properties or a compound index (I can see myself getting this wrong):

  // Add separate indexes for name and timestamp.
  // Also add a compound index for name and timestamp.
  #Index<Item>([\.name], [\.timestamp], [\.name, \.timestamp])

The compound index would be useful if my items had duplicate names that I wanted to sort in timestamp order.

Learn More