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] = []
}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)
}
}
}- What is Vein
- Getting Started & Docs
- Why Vein
- Sponsoring, Alternative Licensing & CLA
- Third Party Licenses
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:
- SwiftData is restricted: It is closed-source, limited to Apple platforms, and heavily reliant on implicit runtime magic that can be difficult to debug.
- Core Data is dated: It's old, doesn't integrate nicely with declarative UI frameworks and like SwiftData it's limited to Apple's platforms.
- Realm is deprecated & Apple-locked: With MongoDB deprecating the Atlas Device SDK (Realm's sync engine), a massive gap has been left for cross-platform sync. Additionally, while Realm has SDKs for other languages, the
RealmSwiftSDK 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. - Cross-platform Swift is growing: With the rise of Swift on Android, Windows, Linux, and embedded systems, there is a critical need for a modern, local-first, thread-agnostic ORM where the exact same Swift models compile and run on every platform.
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.
- Unified Core:
VeinCore,VeinSwiftUI, andVeinSCUIare lightweight, platform-specific wrappers around the single,Veintarget. - Consistent Macros: The Swift macros generate identical model code on every OS. The only difference is additive, framework-specific code for UI reactivity (like SwiftUI vs. SwiftCrossUI).
- Zero Engine Drift: The only platform-specific implementation detail is secure database key storage.
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.
- Zero-Boilerplate Schemas: No need to manually define your database schema (unlike Fluent for example). Vein generates all information it needs automatically from your model declarations using the
@Modelmacro at compile time. - Identity Map: Ensures a maximum of one in-memory class instance per database row and context.
- Declarative Migrations: Schema migrations between versions are declared similarly to SwiftData. No raw SQL required. Every migration has to be declared explicitly and if any data is left unhandled the migration fails and rolls back. For the simple migrations there are single line helper functions.
- UI Reactivity: Out-of-the-box bindings for modern declarative UI frameworks.
- Foundation.Predicate based filters & custom SQL: You can use either the
#Predicatemacro or write a custom SQLExpression & runtime filter separately. - Control over time of fetch: By default all fields are eager loaded. For bigger blobs, texts or data you just don't need that often, you can apply
@LazyFieldto the property, then it will be fetched on first access.
Vein provides a lightweight transaction API that directly wraps SQL transactions:
- Guaranteed DB Rollback: If a transaction fails, the underlying persistence layer is guaranteed to roll back safely, even when you called
context.save()multiple times. - In-Memory State: SQL transactions do not automatically revert in-memory Swift object mutated states. To sync your in-memory objects back to the database state after a failed transaction (if you wish to do so), simply call
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:
- Field-Level Locking: Each individual model property has its own lock, minimizing lock contention.
- Context Synchronization: Access to the
ManagedObjectContextidentity map andcontext.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.
- UI Updates: While model mutation is thread-safe, any resulting UI updates must still be dispatched to the main thread, as is standard.
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.
- Database & Security:
skiptools/swift-sqlcipher(cross platform sqlite and db level encryption) - Credentials:
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 ofDatabaseKeyProvider. - Metadata & Tooling:
swiftlang/swift-syntax(compile time macros),apple/swift-log,apple/swift-atomics(used only in a write once, read a lot place) - Testing:
typelift/SwiftCheckfor property based testing. - SwiftCrossUI: VeinSCUI depends on SwiftCrossUI. It's only used when the trait
VeinSCUIis 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:
- Sponsor on GitHub Sponsors: Help me keep development active and sustainable.
- Alternative/Commercial Licensing: Vein is licensed under the MPL 2.0. Because I utilize a Contributor License Agreement (CLA) to maintain licensing flexibility under the Amethyst Software name, I can offer custom or commercial licensing terms if your organization's legal policies require them. Please reach out to me at mia.koring@amethystsoft.de.
- My CLA Commitment (Safety Hatch): To protect contributors and ensure the project's longevity, the CLA includes a "safety hatch". If Amethyst Software (me) ever stops maintaining the open-source distribution of Vein, all contributors automatically gain the right to redistribute the entire codebase under any OSI-approved license. Your contributions will always remain free and open. Long live Swift, everywhere.
Licenses of third party projects are in the Acknowledgements folder.
- Vein contains a modified copy of yaslab/ULID.swift. The original MIT license can be found in Acknowledgements/ULID-LICENSE.