What SwiftData is, where it sits relative to Core Data, and the three components — @Model, ModelContainer, ModelContext — that everything else in this book builds on. By the end of this part you’ll understand SwiftData’s mental model well enough to know why the later parts are organized the way they are, and you’ll have a model wired into a SwiftUI view. This part deliberately stays high-level; deep treatment of each component comes later.
Everything that goes into designing a single @Model type correctly: attribute options, optionality, defaults, transient properties, enums, custom value types, the new Codable attribute support, uniqueness constraints, and indexes. This is the part to return to whenever you’re starting a new model and want to get the shape right the first time, before relationships or migrations enter the picture.
Covers cardinality and inverses, one-to-many and many-to-many relationships built correctly, one-to-one and unidirectional relationships, the four delete rules, optional relationships and the specific nil-handling crashes they can cause, relationship performance and traversal, and the common mistakes — including circular relationships — that show up once a schema has more than one model type. This part treats relationships as a first-class design problem rather than an afterthought to Part 2's single-model focus. By the end you'll know which delete rule to reach for and why, not just what each one does.
Build a Complete App Everything from Parts 1 through 3 applied to a real, working app — the Book Tracker — built from an empty Xcode project through fetching, inserting, updating, and deleting records, a real bug and its non-obvious root cause, a custom view modifier, storing images correctly, and empty states. This is the part where the theory becomes a screen you can actually use, and the app built here is what every later part in this book continues to extend.
Previews & Mock Data Building realistic sample data for SwiftUI previews without touching a real device's store, the PreviewModifier protocol for caching that sample data across multiple previews, and @Previewable for genuinely interactive previews without a throwaway wrapper view. Short, but worth its own part: every later chapter's code examples lean on these three techniques without re-explaining them.
Querying and Fetching The largest part in the book, and the one most developers will return to most often: @Query's actual mechanics, FetchDescriptor for fetches outside a view, writing and combining predicates (including the iOS 27 enum and sectioned-query additions), sorting, filtering strategy (Swift-side vs. store-side), fetch limits and pagination, querying relationships efficiently, animating query results, and querying from outside SwiftUI entirely — widgets, background code. Treat this part as the reference section for "how do I actually get the data I want."
Swift Concurrency and SwiftData The mental model for isolation domains and why ModelContainer is Sendable while ModelContext isn't, ModelContext's main-actor default, ModelActor for genuine background work, Sendability rules for your own types, importing large datasets safely, and the specific pitfalls — including actor reentrancy — that show up once real concurrent access enters the picture. This part exists because getting it wrong produces crashes that only show up under real load, not in a simple demo — worth reading carefully even if your app feels too small to need it yet.
Observation and Change Tracking The shift from "what does the data look like right now" (@Query) to "what actually changed, and when" (persistent history): HistoryDescriptor, reading the contents of a transaction, tokens for tracking progress and cleaning up old history, and the two new iOS 27 observation tools — ResultsObserver for @Query-like reactivity outside a view, and HistoryObserver for building an actual sync pipeline. Come back to this part the moment you need to know not just the current state of your data, but the story of how it got there.
Migrations What SwiftData migrates automatically and the real boundary where that stops — type changes, never — VersionedSchema and SchemaMigrationPlan, custom migrations with willMigrate/didMigrate, migrating relationships specifically, testing a migration against realistic old data, handling a migration that fails in production, backward compatibility for users skipping several versions at once, and data preservation as a last line of defense. Migrations are where a schema decision made in Part 2 either pays off or costs you later — this is the most consequential part in the book for an app that's already shipped.
CloudKit and iCloud Sync CloudKit's complete, non-negotiable schema requirements, reconciling an existing schema to meet them, container configuration and entitlements, how sync and remote changes actually behave, what CloudKit's conflict resolution really does — and doesn't do, debugging sync failures, the real difference between development and production environments, and migration considerations once CloudKit is live. Written to correct a specific, common assumption: enabling CloudKit is not the same as having a sync architecture.
Custom Data Stores An advanced, narrow part: what DefaultStore actually is, the DataStore protocol's real requirements, and the optional DataStoreBatching and HistoryProviding protocols. Most apps, including this book's own, never need any of this — the part is honest about that up front, and exists for the specific, concrete cases where DefaultStore genuinely isn't enough.
Performance Measuring correctly before optimizing anything — Instruments, not guesses — fetch and predicate efficiency, when indexing actually helps, memory and faulting behavior, the real cost of background imports on the main thread, and CloudKit-specific performance considerations. Every claim in this part is tied to a specific tool or a specific, documented finding — nothing here is "SwiftData is just slow," everything is "here's how to find out why."
Architecture Where SwiftData fits into a real app's structure: the simple @Query-in-views pattern as a legitimate choice, MVVM done properly — and why it genuinely conflicts with @Query — repositories and service layers, networking and caching, offline-first design, sync architecture beyond CloudKit's own integration, and what changes once an app is genuinely large. No single architecture is prescribed — every chapter argues for introducing structure only when a concrete need justifies it.
Testing A complete testing discipline built on in-memory containers: model tests, query tests, relationship tests, migration tests, concurrency tests — and the honest limits of what they can prove — persistence integration tests, and what's actually verifiable about CloudKit sync without a live account. Every test in this part targets your own logic, never SwiftData's own, already-guaranteed mechanics.
Debugging Practical, pattern-recognition-based debugging for the failures a real SwiftData app eventually produces: schema and relationship errors, predicate and migration failures, CloudKit sync and concurrency problems, unexpected saves and missing updates, and store corruption itself. Built around real, confirmed error messages and documented incidents rather than generic troubleshooting advice — the part to open first when something is actually broken.