🔍

How to Batch Delete Data in SwiftData

TL;DR: Need to efficiently delete thousands of records in SwiftData? Instead of iterating through the ModelContext, use the delete(model:where:) API to bypass object creation overhead and clean up data in seconds.

The Problem

In Core Data, batch operations are a powerful tool. They allow developers to bypass the Context and operate directly on the Persistent Store, significantly improving performance during data manipulation. Does SwiftData offer similar capabilities?

Understanding Batch Operations

In both SwiftData and Core Data, most standard data operations occur through the ModelContext. The context is responsible for converting persistent data into Swift type instances defined by the developer, while also maintaining the Object Graph and data relationships.

While powerful, these mechanisms (such as instantiating objects and tracking relationships) incur significant memory and CPU overhead. When dealing with large datasets, loading and deleting items one by one can lead to severe performance degradation and even UI hangups (hitches).

The core concept of Batch Operations is to bypass the context entirely and send instructions directly to the persistence layer, thereby drastically increasing execution speed.

Using the delete Method

SwiftData provides a batch deletion API that is more modern and type-safe than its Core Data counterpart.

Swift
func delete<T>(
    model: T.Type,
    where predicate: Predicate<T>? = nil, // Filter criteria; nil deletes everything
    includeSubclasses: Bool = true // Whether to include subclass data
) throws where T : PersistentModel

1. Deleting All Data of a Specific Type

Developers can use the following code to instantly clear all data in the Item table:

Swift
// Delete all data for the Item type
try? modelContext.delete(model: Item.self)
// You must save the context for the changes to take effect
try? modelContext.save()

Note: Unlike the standard single-object deletion modelContext.delete(_ model: T), batch deletion is only applied to the database after save() is executed.

Thanks to SwiftData’s built-in support for Persistent History Tracking, the context in memory automatically detects changes after a batch deletion, requiring no manual synchronization.

2. Batch Deletion with Conditions

To delete data that matches specific criteria, simply combine the method with the Swift #Predicate macro:

Swift
// Delete all SubItems where the name is "abc"
let predicate = #Predicate<SubItem> {
    $0.name == "abc"
}

try? modelContext.delete(model: SubItem.self, where: predicate)
try? modelContext.save()

Just like Core Data, SwiftData’s batch deletion automatically respects Cascade Deletion rules. If Item has relationships with other models and deletion rules are configured, the associated data will also be cleaned up.

3. Handling Data Inheritance

SwiftData supports model inheritance. When deleting parent class data, the default behavior is to also delete data belonging to its subclasses. If you only want to delete the data strictly associated with the parent class (in specific data model designs), you can set includeSubclasses to false.

Swift
@Model
class Item {
    var timestamp: Date
    
    init(timestamp: Date) {
        self.timestamp = timestamp
    }
}

@available(iOS 26, *)
@Model
final class SubItem: Item { // Subclass of Item
    var name: String

    init(name: String) {
        self.name = name
        super.init(timestamp: .now)
    }
}

// Only delete base records in the Item table, preserving SubItem data
try? modelContext.delete(model: Item.self, includeSubclasses: false) 
try? modelContext.save()

Limitations: Batch Insert and Update

Although Swift 6 and iOS 26 have brought many improvements, as of now, SwiftData natively supports only batch deletion. It does not yet provide native APIs for Batch Update or Batch Insert.

Since SwiftData and Core Data share the exact same underlying storage structure (SQLite), if your application demands extreme performance for batch updates or insertions, you can achieve this by mixing in Core Data’s NSBatchUpdateRequest or NSBatchInsertRequest.

For specific implementation strategies, refer to: How to Use Batch Operations in Core Data.

Related Tips

Subscribe to Fatbobman

Weekly Swift & SwiftUI highlights. Join developers.

Subscribe Now