Cross platform declarative DB framework for apps, inspired by SwiftData, refined by us.
46
stars
261
commits
Swift
primary language
Sep 10, 2026
updated
A familiar API, built better and open. Vein brings a refined, SwiftData-like interface to Apple, Linux, Android, and Windows, powered by a completely rewritten, highly optimized backend.
Table of Contents Docs and Tutorials
enum V0_0_1: VersionedSchema {
static let version = ModelVersion(0, 0, 1)
static let models: [any PersistentModel.Type] = [
Post.self,
Attachment.self
]
@Model
final class Post {
var title: String
var content: String
@Relationship(
inverse: \Attachment.post,
deleteRule: .cascade
)
var attachments: [Attachment]
init(title: String, content: String) {
self.title = title
self.content = content
}
}
@Model
final class Attachment {
@Relationship
var post: Post?
var name: String
var fileType: FileType
var sizeMiB: Double
@LazyField
var data: Data?
init(name: String, fileType: FileType, data: Data) {
self.name = name
self.fileType = fileType
self.sizeMiB = Double(data.count) / 1024 / 1024
self.data = data
}
enum FileType: String, RawRepresentablePersistable {
case png
case jpg
case gif
case swift
// ...
}
}
}
typealias Post = V0_0_1.Post
typealias Attachment = V0_0_1.Attachment
enum Migration: SchemaMigrationPlan {
static let schemas: [VersionedSchema.Type] = [
V0_0_1.self
]
static let stages: [MigrationStage] = []
}
[!IMPORTANT] Using Vein with macOS 13 or iOS, tvOS or macCatalyst 16 requires the "VeinFilter" trait to be enabled. Then you can use
#Filterinstead of#Predicate
func setupAndUseVein() throws {
// Optional: Setup keyring for Linux support
#if os(Linux)
Keyring.appIdentifier.withLock { $0 = "com.example.app" }
#endif
let container = try ModelContainer(
V0_0_1.self, // Your VersionedSchema
migration: Migration.self, // Your SchemaMigrationPlan
at: "path/to/db.sqlite3", // or nil for in memory
appID: "com.example.app" // The id of your app
)
try container.migrate()
let post = Post(title: "How to use Vein?", content: "It's very easy.")
try container.context.insert(post)
post.content = "What did I tell you?"
try container.context.save()
let posts = try container.context.fetchAll(#Predicate<Post> { post in
post.title.contains("Vein")
}) // gives back [post]
try container.context.delete(post)
}
More here: SwiftUI SwiftCrossUI
struct ContentView: View {
@Query(#Predicate<Post> { post in
post.title.contains("Swift")
})
var posts: [Post]
@Environment(\.modelContext) var context
var body: some View {
Button("Add post") {
do {
try context.insert(Post(title: "New Post", content: "..."))
try context.save()
} catch {
// Update some error state.
}
}
List(posts) { post in
Text(post.title)
}
}
}
Vein is a local first, highly abstracted ORM for Swift, backed by an SQLite (+ SQLCipher) database. Its API is heavily inspired by Apple's SwiftData framework.
Unlike SwiftData, Amethyst Vein is open source and aims to use the least amount of runtime magic possible while still providing a very user-friendly API. It is also compatible with every major consumer OS (Apple, Android, Linux and Windows), SwiftUI, SwiftCrossUI and functions independent of UI framework too, just without automatic reactivity.
You can find our tutorials and docs at vein.amethystsoft.de.
Amethyst Vein was built out of frustration with the current state of local persistence in the Swift ecosystem:
RealmSwift SDK relies heavily on the Objective-C runtime (more than 50% objc code in RealmSwift). This makes it virtually impossible to compile your Swift models on Android, Linux, or Windows. And it just doesn't feel as nice as SwiftData.Vein is backed by the exact same SQLite + SQLCipher database engine across every platform. Unlike other frameworks that wrap Apple-exclusive APIs on iOS and switch engines elsewhere, Vein shares its entire core logic globally.
VeinCore, VeinSwiftUI, and VeinSCUI are lightweight, platform-specific wrappers around the single, Vein target.This architectural consistency guarantees the exact same behavior, performance, and migration stability no matter where you're running it.
Vein's long-term goal is to fill the void left by Realm's deprecation. We aim to construct a platform-independent sync engine that provides the same seamless device-to-cloud experience, but with privacy at its core via end-to-end encryption (E2EE) and selfhostability.
@Model macro at compile time.#Predicate macro or write a custom SQLExpression & runtime filter separately.@LazyField to the property, then it will be fetched on first access.Vein provides a lightweight transaction API that directly wraps SQL transactions:
context.save() multiple times.context.rollback().Unlike Core Data or SwiftData, which enforce strict thread-confinement rules, Vein models are thread-safe and can be shared and mutated freely across threads.
Vein achieves thread agnosticism synchronously through the heavy use of unfair locks:
ManagedObjectContext identity map and context.save() operations are synchronized via locks.[!IMPORTANT] Performance Tip: Because saving is blocking and synchronized, calling
context.save()on the main thread while a background save is already in progress on the same context will block the main thread until the background save completes. For heavy concurrent write operations, we recommend using dedicated, short-lived child contexts.
Relationships only eager load the ULIDs. Model instances will be resolved on access through the context. That ensures both low initial load times and prevents memory leaks while still keeping use easy.
Vein models do not conform to Codable. Since Vein knows all fields at compile time via the @Model macro, it bypasses Codable entirely.
You can create an in memory database by passing nil as path to a ModelContainer. Also Vein comes with a small Test helper in VeinTesting, reducing the code you need to write yourself. See the migration unit testing tutorial.
Each context.save() is atomic per context and happens inside an SQL transaction.
We generally recommend not to save the same models on multiple threads concurrently, for error handling becoming annoying alone.
Vein is designed to be highly portable, relying on standard Swift Evolution tools, cross platform wrappers and platform specific tools (for storing encryption keys), to make usage as seemless as possible for you.
skiptools/swift-sqlcipher (cross platform sqlite and db level encryption)kishikawakatsumi/keychainaccess (Apple), amethystsoft/KeyringAccess (our own lib for storing credentials in SecretService on Linux) and a Vein internal wrapper for CredW from the WinSDK on windows. Currently we don't support db level encryption on android automatically due to difficulties with storing keys safely caused by the way android is build. You can use your own implementation of DatabaseKeyProvider.swiftlang/swift-syntax (compile time macros), apple/swift-log, apple/swift-atomics (used only in a write once, read a lot place)typelift/SwiftCheck for property based testing.VeinSCUI is active.Amethyst Vein is independent open source. Swift and an open ecosystem are incredibly important to me. My goal is to strengthen the cross-platform Swift ecosystem (including my work as a core contributor to SwiftCrossUI). I currently work on these projects without traditional funding.
If Vein is valuable to your business, please consider supporting its development:
Licenses of third party projects are in the Acknowledgements folder.
Swift
99.7%
Cross platform declarative DB framework for apps, inspired by SwiftData, refined by us.
46
stars
261
commits
Swift
primary language
Sep 10, 2026
updated
A familiar API, built better and open. Vein brings a refined, SwiftData-like interface to Apple, Linux, Android, and Windows, powered by a completely rewritten, highly optimized backend.
Table of Contents Docs and Tutorials
enum V0_0_1: VersionedSchema {
static let version = ModelVersion(0, 0, 1)
static let models: [any PersistentModel.Type] = [
Post.self,
Attachment.self
]
@Model
final class Post {
var title: String
var content: String
@Relationship(
inverse: \Attachment.post,
deleteRule: .cascade
)
var attachments: [Attachment]
init(title: String, content: String) {
self.title = title
self.content = content
}
}
@Model
final class Attachment {
@Relationship
var post: Post?
var name: String
var fileType: FileType
var sizeMiB: Double
@LazyField
var data: Data?
init(name: String, fileType: FileType, data: Data) {
self.name = name
self.fileType = fileType
self.sizeMiB = Double(data.count) / 1024 / 1024
self.data = data
}
enum FileType: String, RawRepresentablePersistable {
case png
case jpg
case gif
case swift
// ...
}
}
}
typealias Post = V0_0_1.Post
typealias Attachment = V0_0_1.Attachment
enum Migration: SchemaMigrationPlan {
static let schemas: [VersionedSchema.Type] = [
V0_0_1.self
]
static let stages: [MigrationStage] = []
}
[!IMPORTANT] Using Vein with macOS 13 or iOS, tvOS or macCatalyst 16 requires the "VeinFilter" trait to be enabled. Then you can use
#Filterinstead of#Predicate
func setupAndUseVein() throws {
// Optional: Setup keyring for Linux support
#if os(Linux)
Keyring.appIdentifier.withLock { $0 = "com.example.app" }
#endif
let container = try ModelContainer(
V0_0_1.self, // Your VersionedSchema
migration: Migration.self, // Your SchemaMigrationPlan
at: "path/to/db.sqlite3", // or nil for in memory
appID: "com.example.app" // The id of your app
)
try container.migrate()
let post = Post(title: "How to use Vein?", content: "It's very easy.")
try container.context.insert(post)
post.content = "What did I tell you?"
try container.context.save()
let posts = try container.context.fetchAll(#Predicate<Post> { post in
post.title.contains("Vein")
}) // gives back [post]
try container.context.delete(post)
}
More here: SwiftUI SwiftCrossUI
struct ContentView: View {
@Query(#Predicate<Post> { post in
post.title.contains("Swift")
})
var posts: [Post]
@Environment(\.modelContext) var context
var body: some View {
Button("Add post") {
do {
try context.insert(Post(title: "New Post", content: "..."))
try context.save()
} catch {
// Update some error state.
}
}
List(posts) { post in
Text(post.title)
}
}
}
Vein is a local first, highly abstracted ORM for Swift, backed by an SQLite (+ SQLCipher) database. Its API is heavily inspired by Apple's SwiftData framework.
Unlike SwiftData, Amethyst Vein is open source and aims to use the least amount of runtime magic possible while still providing a very user-friendly API. It is also compatible with every major consumer OS (Apple, Android, Linux and Windows), SwiftUI, SwiftCrossUI and functions independent of UI framework too, just without automatic reactivity.
You can find our tutorials and docs at vein.amethystsoft.de.
Amethyst Vein was built out of frustration with the current state of local persistence in the Swift ecosystem:
RealmSwift SDK relies heavily on the Objective-C runtime (more than 50% objc code in RealmSwift). This makes it virtually impossible to compile your Swift models on Android, Linux, or Windows. And it just doesn't feel as nice as SwiftData.Vein is backed by the exact same SQLite + SQLCipher database engine across every platform. Unlike other frameworks that wrap Apple-exclusive APIs on iOS and switch engines elsewhere, Vein shares its entire core logic globally.
VeinCore, VeinSwiftUI, and VeinSCUI are lightweight, platform-specific wrappers around the single, Vein target.This architectural consistency guarantees the exact same behavior, performance, and migration stability no matter where you're running it.
Vein's long-term goal is to fill the void left by Realm's deprecation. We aim to construct a platform-independent sync engine that provides the same seamless device-to-cloud experience, but with privacy at its core via end-to-end encryption (E2EE) and selfhostability.
@Model macro at compile time.#Predicate macro or write a custom SQLExpression & runtime filter separately.@LazyField to the property, then it will be fetched on first access.Vein provides a lightweight transaction API that directly wraps SQL transactions:
context.save() multiple times.context.rollback().Unlike Core Data or SwiftData, which enforce strict thread-confinement rules, Vein models are thread-safe and can be shared and mutated freely across threads.
Vein achieves thread agnosticism synchronously through the heavy use of unfair locks:
ManagedObjectContext identity map and context.save() operations are synchronized via locks.[!IMPORTANT] Performance Tip: Because saving is blocking and synchronized, calling
context.save()on the main thread while a background save is already in progress on the same context will block the main thread until the background save completes. For heavy concurrent write operations, we recommend using dedicated, short-lived child contexts.
Relationships only eager load the ULIDs. Model instances will be resolved on access through the context. That ensures both low initial load times and prevents memory leaks while still keeping use easy.
Vein models do not conform to Codable. Since Vein knows all fields at compile time via the @Model macro, it bypasses Codable entirely.
You can create an in memory database by passing nil as path to a ModelContainer. Also Vein comes with a small Test helper in VeinTesting, reducing the code you need to write yourself. See the migration unit testing tutorial.
Each context.save() is atomic per context and happens inside an SQL transaction.
We generally recommend not to save the same models on multiple threads concurrently, for error handling becoming annoying alone.
Vein is designed to be highly portable, relying on standard Swift Evolution tools, cross platform wrappers and platform specific tools (for storing encryption keys), to make usage as seemless as possible for you.
skiptools/swift-sqlcipher (cross platform sqlite and db level encryption)kishikawakatsumi/keychainaccess (Apple), amethystsoft/KeyringAccess (our own lib for storing credentials in SecretService on Linux) and a Vein internal wrapper for CredW from the WinSDK on windows. Currently we don't support db level encryption on android automatically due to difficulties with storing keys safely caused by the way android is build. You can use your own implementation of DatabaseKeyProvider.swiftlang/swift-syntax (compile time macros), apple/swift-log, apple/swift-atomics (used only in a write once, read a lot place)typelift/SwiftCheck for property based testing.VeinSCUI is active.Amethyst Vein is independent open source. Swift and an open ecosystem are incredibly important to me. My goal is to strengthen the cross-platform Swift ecosystem (including my work as a core contributor to SwiftCrossUI). I currently work on these projects without traditional funding.
If Vein is valuable to your business, please consider supporting its development:
Licenses of third party projects are in the Acknowledgements folder.
Swift
99.7%