Slate 3 (2026)

Slate 3 is the version I always wanted to write but couldn’t until Swift gained macros, and AI was able to help do the heavy lifting to connect them to code generators and unit tests.

Slate 2 had a good API, but the data model still lived in an .xcdatamodeld file that you edited in Xcode’s graphical editor, and a code generator would slurp the XML and emit Swift. It worked, but the editor was finicky, and you were always context-switching between Swift and a GUI to make small changes.

SwiftData fixed this in its own way by inventing @Model, but SwiftData also throws away the immutability story that’s the entire point of Slate. Slate 3 uses macros to get SwiftData’s ergonomics without giving up the read-only, Sendable model surface:

@SlateEntity
public struct Patient {
    public let patientId: String
    public let firstName: String
    public let lastName: String
    public let age: Int?
}

slate-generator reads the annotated structs and emits both the NSManagedObject subclasses that Core Data needs internally and the bridge code that maps between them and the immutable Patient value you’ll see in your app. No .xcdatamodeld file. No GUI editor.

Access is async/await throughout, with the completion-based holdovers from earlier versions stripped out:

let adults = try await slate.many(Patient.self, where: \.age >= 18, sort: [\.lastName])

Every public type is Sendable. Mutability is a private implementation detail of the persistence layer, and the rest of the app never sees a mutable model.

Source on github.