GRDB.swift
SQLite toolkit for Swift — covers the full spectrum from raw SQL to Swift-idiomatic ORM. GRDB provides: DatabaseQueue (serial SQLite access), DatabasePool (concurrent readers/serial writer), record types (FetchableRecord, PersistableRecord, TableRecord), migration support, query builder DSL, Combine publishers for reactive observation, and Swift async/await API. Alternative to Core Data and SQLite.swift for iOS/macOS. GRDB prioritizes SQLite's full power — write real SQL or use Swift query builder. DatabaseObservation (ValueObservation) notifies on database changes. Used widely in iOS agent apps requiring offline storage.
Score Breakdown
⚙ Agent Friendliness
🔒 Security
Local SQLite — no network exposure. SQLite database file in app's Documents directory is backed up to iCloud by default; use NSFileProtectionComplete and opt out of iCloud backup for sensitive agent data. GRDB + SQLCipher extension provides encryption at rest for agent sensitive data.
⚡ Reliability
Best When
You're building an iOS/macOS agent app that needs reliable SQLite storage with Swift-idiomatic API and real SQL power — GRDB is the most complete SQLite toolkit for Swift with excellent async support.
Avoid When
You need iCloud sync (use Core Data + CloudKit), you're targeting iOS 17+ only (consider SwiftData), or you need cross-platform storage.
Use Cases
- • Store agent conversation history in SQLite on iOS/macOS using GRDB — Agent struct conforming to FetchableRecord + PersistableRecord enables agent.save(db) and Agent.fetchAll(db) without Core Data setup overhead
- • Observe agent data changes reactively with GRDB ValueObservation — ValueObservation.tracking { Agent.fetchAll($0) }.publisher(in: dbQueue) emits updated agent list whenever database changes
- • Write complex agent search queries with GRDB SQL interpolation — try Agent.fetchAll(db, sql: 'SELECT * FROM agents WHERE status = ? ORDER BY created_at DESC', arguments: ['active']) for type-safe parameterized SQL
- • Database migrations for agent schema evolution — DatabaseMigrator with numbered migrations ensures agent database schema is always up-to-date on app launch
- • Concurrent agent data reads with DatabasePool — multiple reader threads read agent data concurrently; writer uses serial queue; DatabasePool maximizes read throughput for agent-heavy read workloads
Not For
- • Cloud sync or server-side — GRDB is local SQLite only; use CloudKit/Firebase for synced agent data; Core Data for CloudKit integration (NSPersistentCloudKitContainer)
- • SwiftData (iOS 17+) projects — Apple's SwiftData is the modern replacement for Core Data with Swift-native API; for new iOS 17+ agent apps, evaluate SwiftData first unless you need GRDB's SQL control
- • Non-Apple platforms — GRDB is Apple platform only (iOS, macOS, watchOS, tvOS); use SQLite.swift or Room (Android) for cross-platform agent database needs
Interface
Authentication
Local SQLite library — no auth concepts. SQLite file encryption via SQLCipher integration for sensitive agent data at rest.
Pricing
GRDB.swift is MIT licensed, maintained by Gwendal Roué. Free for all use including commercial apps.
Agent Metadata
Known Gotchas
- ⚠ DatabaseQueue vs DatabasePool choice matters — DatabaseQueue allows one reader at a time (concurrent reads block); DatabasePool allows multiple concurrent readers; for agent apps with frequent background reads, always use DatabasePool to prevent UI blocking
- ⚠ ValueObservation captures scheduling — ValueObservation.publisher(in: dbQueue) emits on DatabaseQueue's writer thread by default; add .receive(on: DispatchQueue.main) for UI updates; missing main thread dispatch causes agent UI update from background thread
- ⚠ Transactions must be explicit for multi-step agent writes — multiple agent record saves without explicit transaction create N separate SQLite transactions; wrap in db.transaction { } for atomicity and 10-100x performance improvement for bulk agent data writes
- ⚠ PersistableRecord databaseTableName must match schema — default tableName is lowercased struct name; Agent maps to 'agent' table; schema using 'agents' (plural) requires explicit static var databaseTableName = 'agents'
- ⚠ Migration renaming requires care — DatabaseMigrator runs migrations by name in order; renaming a migration in code leaves applied migration history in grdb_migrations table with old name; new migration name runs again causing duplicate schema changes in agent database
- ⚠ Cursor vs array fetch for large agent datasets — Agent.fetchAll(db) loads all agents into memory at once; Agent.fetchCursor(db) returns lazy cursor for large datasets; always use fetchCursor for agent datasets >10k rows to avoid memory spikes
Alternatives
Full Evaluation Report
Detailed scoring breakdown, competitive positioning, security analysis, and improvement recommendations for GRDB.swift.
Scores are editorial opinions as of 2026-03-06.