SwiftData is Apple's modern, declarative persistence framework designed to integrate seamlessly with Swift and SwiftUI. It replaces the complex XML mapping files and heavy boilerplate of Core Data with a modern, compile-time type-safe API. You define your schema using standard Swift classes annotated with the `@Model` macro. SwiftData automatically handles relationships, migrations, constraints, and persistence behind the scenes, allowing you to focus on your app's business logic.
The architecture revolves around three main components: models, containers, and contexts. Your models conform to `PersistentModel` via the `@Model` macro. A `ModelContainer` manages the persistent store (usually SQLite on disk) and translates your schema definitions into tables, columns, and relations. To fetch, insert, update, or delete records, you interact with a `ModelContext`, which tracks changes in memory until you save them. This state management integrates directly into SwiftUI, where property wrappers like `@Query` automatically keep your views synchronized with the underlying database.
For advanced database operations, SwiftData provides robust tools for fetching, migration, and concurrency. You query models using `FetchDescriptor`, defining precise search criteria, sort orders, and pre-fetching rules. Schema changes are managed using `VersionedSchema` and `SchemaMigrationPlan`, supporting both automatic lightweight migrations and complex custom stages. For background operations, conforming to the `ModelActor` protocol ensures that database queries are isolated to serial background actors, preventing thread safety violations and main thread blocking.
Get started
Define a model, set up a container, and perform basic CRUD operations
import SwiftData
import Foundation
// Define a persistable Swift class using the @Model macro
@Model
class TodoItem {
@Attribute(.unique) var id: UUID
var title: String
var isCompleted: Bool
init(title: String) {
self.id = UUID()
self.title = title
self.isCompleted = false
}
}
// Initialize a ModelContainer (holds the schema and SQLite database configuration)
let container = try ModelContainer(for: TodoItem.self)
// Get the main context (typically on the main thread for UI interaction)
let context = container.mainContext
// 1. Create: Insert a new item
let newItem = TodoItem(title: "Buy groceries")
context.insert(newItem)
try context.save() // Commit changes to the persistent store
// 2. Read: Fetch items using a FetchDescriptor
let descriptor = FetchDescriptor<TodoItem>(predicate: #Predicate { !$0.isCompleted })
let openTodos = try context.fetch(descriptor)
assert(openTodos.count == 1)
// 3. Update: Modify properties directly
newItem.isCompleted = true
try context.save() // SwiftData tracks the change and saves automatically
// 4. Delete: Remove the item from the context
context.delete(newItem)
try context.save()Key concepts
Macro-Driven Schema
By annotating standard Swift classes with `@Model`, the compiler automatically generates conformances to `PersistentModel`. This macro instruments your properties with getter/setter hooks that load data from disk on-demand, handle relationships automatically, and track unsaved modifications.
Contextual Modification Tracking
A `ModelContext` acts as an in-memory scratchpad for your database. As you modify model instances, insert new items, or delete old ones, the context tracks these changes. Calling `save()` pushes these modifications to the database in a single atomic transaction.
Query Integration in SwiftUI
SwiftData is built to power SwiftUI. The `@Query` property wrapper in a view automatically performs fetches and registers the view for updates. When data changes in the underlying store, the view is automatically updated to reflect the new state.
Compiler-Enforced Actor Concurrency
To safely work with databases off the main thread, SwiftData utilizes Swift's actor model. By conforming to `ModelActor`, you create a background worker that has its own isolated `ModelContext` running on a private serial executor, eliminating cross-thread data corruption.
Essentials 6
The core components you need to initialize SwiftData, define persistent model classes, configure target storage locations, and perform basic context operations.
- PrPersistentModeliOS 17+A protocol applied automatically by the `@Model` macro to turn standard Swift classes into persistent objects managed by SwiftData. It provides tracking for changes, relationship resolution, and lazy property loading.persistentModelIDmodelContexthasChanges
@Model class Book { var title: String init(title: String) { self.title = title } } - ClModelContaineriOS 17+An object that manages the persistent store and holds the database schemas. It initializes the database at a target file URL and provides model contexts for your app.init(for:configurations:)mainContextconfigurationsdeleteAllData()
let container = try ModelContainer(for: Book.self) - ClModelContextiOS 17+An object that serves as the primary workspace for database operations. It tracks inserted, modified, and deleted models, and commits changes to the underlying storage during saving.insert(_:)delete(_:)save()fetch(_:)hasChangesundoManager
let context = container.mainContext context.insert(Book(title: "SwiftUI by Example")) try context.save() - StModelConfigurationiOS 17+A value that configures the storage location, group permissions, cloud sync capabilities, and read-only status of a persistent store backing your container.urlnameisStoredInMemoryOnlyallowsCloudKitSync
let config = ModelConfiguration(isStoredInMemoryOnly: true) let container = try ModelContainer(for: Book.self, configurations: config) - StPersistentIdentifieriOS 16+A stable, unique identifier referencing a persistent model object across app runs and threads. Safe to pass between model contexts on different actors.storeIdentifierentityName
let bookID = book.persistentModelID let safeBook = context.model(for: bookID) as? Book - ClSchemaiOS 17+An object that maps model classes to data in the model store, and helps with the migration of that data
Fetching Data 5
Types and descriptors used to query the database, filter records with compiler-verified predicates, sort results, and observe collection changes.
- StFetchDescriptoriOS 17+A structure describing the search query parameters, sort descriptors, pagination offsets, and pre-fetching rules used to fetch persistent models from a context.predicatesortByfetchLimitfetchOffsetpropertiesToFetch
let descriptor = FetchDescriptor<Book>( predicate: #Predicate { $0.title.contains("Swift") } ) let books = try context.fetch(descriptor) - StFetchResultsCollectioniOS 17+A collection that efficiently provides the results of a completed fetch.
- StResultsSectioniOS 27+A section of fetched results grouped by a common section key path value.
- StResultsSectionCollectioniOS 27+A collection of sections as returned by ``ResultsObserver/sections`` or `Query.sections`.
- ClResultsObserveriOS 27+Observes and tracks changes to a collection of persistent models in a model context.
Schema Definition 3
Protocols and structures that describe how properties are mapped, relationships between models are linked, and how backing data is structured.
- PrSchemaPropertyiOS 17+An interface for describing a property.
- PrRelationshipCollectioniOS 17+A protocol describing a collection of related persistent models in a relationship.
- PrBackingDataiOS 17+An interface for providing in-memory storage for a persistent model.
Schema Migration 3
Classes and plans for versioning your schemas and running migrations to evolve your database safely across app updates.
- PrVersionedSchemaiOS 17+A protocol defining a snapshot of your database schema at a specific version. Used to organize and execute sequential database migrations.versionIdentifiermodels
enum BookSchemaV1: VersionedSchema { static var versionIdentifier: Schema.Version = .init(1, 0, 0) static var models: [any PersistentModel.Type] = [Book.self] } - PrSchemaMigrationPlaniOS 17+A protocol that describes the sequence of versioned schemas and specifies the stages (lightweight or custom) needed to migrate user data between versions.schemasstages
struct BookMigrationPlan: SchemaMigrationPlan { static var schemas: [any VersionedSchema.Type] = [BookSchemaV1.self, BookSchemaV2.self] static var stages: [MigrationStage] = [MigrationStage.lightweight(from: BookSchemaV1.self, to: BookSchemaV2.self)] } - EnMigrationStageiOS 17+An enum describing a lightweight (automatic) or custom (run by code) step inside a schema migration plan to perform data transformations..lightweight(from:to:).custom(from:to:willMigrate:didMigrate:)
let stage = MigrationStage.custom(from: V1.self, to: V2.self, willMigrate: { context in // Run custom SQL or modify data before schema updates }, didMigrate: nil)
Concurrency 5
APIs and protocols designed to run database operations safely in the background, isolating context instances using Swift actors.
- PrModelActoriOS 17+A protocol that isolates database access to a serial background actor, facilitating thread-safe database operations in the background.modelContainermodelExecutormodelContext
actor BackgroundImporter: ModelActor { let modelContainer: ModelContainer let modelExecutor: any ModelExecutor init(container: ModelContainer) { self.modelContainer = container self.modelExecutor = DefaultSerialModelExecutor(modelContext: ModelContext(container)) } } - PrModelExecutoriOS 17+An interface for performing storage-related tasks using an isolated model context.
- PrSerialModelExecutoriOS 17+An interface for performing serial storage-related tasks using an isolated model context.
- ClDefaultSerialModelExecutoriOS 17+An object that safely performs storage-related tasks using an isolated model context.
- StEditingStateiOS 18+A value that describes the editing state of a model context's pending changes.
Persistent History 15
APIs for observing and replaying change transactions (inserts, updates, deletes) recorded in the store's persistent history stream.
- StHistoryDescriptoriOS 18+A type that defines which persistent history transactions to fetch and how to bound them.
- PrHistoryProvidingiOS 18+A protocol for data stores that vend persistent history transactions.
- ClHistoryObserveriOS 27+Monitors a model container's data stores for remote changes and notifies
- PrHistoryTokeniOS 18+A protocol that represents a position marking how far history has been read.
- StDefaultHistoryTokeniOS 18+The built-in token marking a position in the store's persistent history.
- PrHistoryTransactioniOS 18+A protocol that describes a group of changes recorded together in persistent history.
- StDefaultHistoryTransactioniOS 18+The built-in type representing a transaction recorded in persistent history.
- EnHistoryChangeiOS 18+An enumeration of the kinds of change—insert, update, or delete—recorded in persistent history.
- PrHistoryInsertiOS 18+A protocol that describes an insertion recorded in the store's persistent history.
- StDefaultHistoryInsertiOS 18+The built-in type representing an insertion recorded in persistent history.
- PrHistoryUpdateiOS 18+A protocol that describes an update recorded in the store's persistent history.
- StDefaultHistoryUpdateiOS 18+The built-in type representing an update recorded in persistent history.
- PrHistoryDeleteiOS 18+A protocol that describes a deletion recorded in the store's persistent history.
- StDefaultHistoryDeleteiOS 18+The built-in type representing a deletion recorded in persistent history.
- StHistoryTombstoneiOS 18+A record that preserves selected values of a model that was deleted from the store.
Custom Data Stores 12
Protocols and types that allow you to implement custom persistence backends, swapping SQLite out for your own custom file format or server API.
- PrDataStoreiOS 18+A protocol you adopt to implement a custom backing store for SwiftData models.
- ClDefaultStoreiOS 18+The built-in data store that persists SwiftData models on Core Data.
- PrDataStoreConfigurationiOS 18+A protocol that describes the configuration of a custom data store.
- PrDataStoreBatchingiOS 18+A protocol that adds batch-operation support, such as batch deletes, to a custom data store.
- PrDataStoreSnapshotiOS 18+A protocol that represents a point-in-time copy of a model's values in a custom store.
- StDefaultSnapshotiOS 18+The built-in snapshot type capturing a model's values at a point in time.
- EnDataStoreSnapshotCodingKeyiOS 18+Coding keys used to encode and decode a custom data store's snapshots.
- StDataStoreFetchRequestiOS 18+A request that asks a custom data store to fetch models matching a descriptor.
- StDataStoreFetchResultiOS 18+The result returned by a custom data store for a fetch request.
- StDataStoreSaveChangesRequestiOS 18+A request that asks a custom data store to persist inserted, updated, and deleted models.
- ClDataStoreSaveChangesResultiOS 18+An object that reports the outcome of saving pending changes to a custom data store.
- StDataStoreBatchDeleteRequestiOS 18+A request that asks a custom data store to delete models matching a predicate in bulk.
Document-Based Storage 1
Types that integrate SwiftData persistence with Apple's standard document-based file structures and system file pickers.
- StModelDocumentA document type that uses SwiftData to manage its storage.
Errors 2
Errors thrown by SwiftData operations when database loading, saving, validation, or schema migration steps fail.
- StSwiftDataErroriOS 17+A type that describes a SwiftData error.
- EnDataStoreErroriOS 18+An error thrown by a custom data store while fulfilling a request.
Structures 1
- StQueryiOS 17.0+A property wrapper that fetches a set of models and keeps those models in sync with the underlying
Type Aliases 1
- TyDataStoreSnapshotValue