Core Principles
Record Types Over Raw Rows
It’s generally easier to access a database through “record types” rather than dealing with raw database rows.- Immutability: Records can be value types (structs)
- Memory safety: No hidden state or side effects
- Multi-threading safety: Values can cross threads freely
Raw SQL When You Need It
Complex queries sometimes need to be prototyped in an SQL shell. Once perfected, translating them to a query builder can be painful with no guarantee of success. GRDB lets you use raw SQL whenever it makes sense:The Database as Single Source of Truth
Unlike Core Data (with multiple managed object contexts) or Realm (with per-thread databases), GRDB assumes apps want a reliable and unambiguous storage:- One truth: The database file is authoritative
- Explicit fetches: Records are snapshots, not live objects
- Clear updates: Changes go through explicit save operations
Fetched records behave like an in-memory cache. Your app decides whether to ignore future changes or observe them with
ValueObservation.Focus on Application Developers
GRDB puts all bets on SQLite and front-end GUI applications:- ✓ iOS, macOS, watchOS, tvOS
- ✓ Migrations, database observation, concurrency safety
- ✓ SwiftUI and Combine support
- ✗ Servers, MySQL, or PostgreSQL (out of scope)
Solving Real Problems
Any Swift Type Can Be a Record
Most libraries require you to subclass a root class (NSManagedObject, Realm.Object). This prevents using Swift structs and value types. With GRDB, any type can become a record:Records That Cross Threads
Immutable value records can safely cross threads. No need to pass object IDs like Core Data or Realm:Database Change Notifications
Instead of auto-updating records, GRDB provides ValueObservation to reactively track database changes:- Notifications only for committed changes (saved on disk)
- Changes notified in transaction order
- All changes detected: record methods, raw SQL, triggers, foreign key cascades
Non-Blocking Reads
DatabasePool enables concurrent reads, so long-running writes don’t block UI queries:Concurrency Comparison
How different libraries handle multi-threading challenges:| Library | Concurrent Writes | Isolation | Conflicts | Blocked UI |
|---|---|---|---|---|
| FMDB (FMDatabase) | App handles | App handles | App handles | App handles |
| FMDB (FMDatabaseQueue) | ✓ | ✓ | App handles | Blocks |
| SQLite.swift | ✓ | App handles | App handles | App handles |
| Core Data | App handles | ✓ | Difficult | App handles |
| GRDB (DatabaseQueue) | ✓ | ✓ | App handles | Blocks |
| GRDB (DatabasePool) | ✓ | ✓ | App handles | ✓ (unless max readers reached) |
Conflicts (same data edited concurrently) are always the app’s responsibility. GRDB provides tools but doesn’t enforce policies.
Never Pay for Using Raw SQL
GRDB’s query interface generates SQL, but you can always drop to raw SQL:- Direct execution
- Record fetching
- Query interface mixing
- Database observation (ValueObservation, Combine, RxSwift)
Performance and Flexibility
For performance-critical code, access raw rows with lazy cursors:Get Started
Installation
Add GRDB to your project
Quick Start
Build your first GRDB app
Demo Apps
Explore example applications
Best Practices
Design patterns and recommendations