Article

SwiftData Query Design Basics

Bitesize

SwiftData gets easier once you stop thinking about queries as a convenience layer and start treating them as part of your data design.

@Query(
  filter: #Predicate<Book> { $0.isArchived == false },
  sort: \Book.title
) private var books: [Book]

The small takeaway is simple: query definitions should describe stable product intent, not temporary screen-level convenience.

More detail

The first mistake teams make with SwiftData is letting each screen invent slightly different fetch rules for what is supposed to be the same concept. That feels harmless at first, but it slowly creates inconsistent behaviour.

A healthier approach is to decide what a list actually represents. Is it all books, active books, recently updated books, or books that belong to one workspace? Once that intent is explicit, the query becomes easier to reason about.

This matters because persistence bugs rarely feel like persistence bugs at the point where users notice them. They usually show up as odd ordering, items appearing in one view but not another, or state that feels inconsistent after an edit.

That is why the query should be narrow and deliberate. A good query tends to mirror the same product language you would use when describing the feature to another person.

Deep dive

SwiftData rewards clarity in model relationships, predicates, and sort order. When those three things line up, the rest of the feature usually becomes calmer.

The practical question is not only whether a query works today. It is whether the same query still makes sense after you add search, filtering, multiple windows, or more complex editing behaviour.

One useful discipline is to keep query intent stable and push transient UI concerns somewhere else. Search text, temporary scopes, and view-local presentation decisions often deserve their own state instead of leaking directly into model semantics.

That separation helps because it keeps your storage language clean. The model describes persisted meaning, while the view describes temporary interaction. Those are related, but they are not the same thing.

SwiftData is most pleasant when the fetch layer feels boring. If your query reads like a durable product rule instead of a one-off workaround, you are usually moving in the right direction.

Finished the deep dive?

You made it to the end.

Mark this article as read once you have worked through the full piece. It is a small way to keep track of what you have genuinely finished.

More in this area

Keep the thread going.

Jump sideways into the related ideas that sit closest to this piece and keep the same mental context alive.

  1. 01 Persistence Explore topic