Platform-agnostic reference shared by mobile-android and mobile-ios.
Couchbase Lite is an embedded JSON document database that runs entirely on-device. It works fully offline and syncs to Couchbase Server via Sync Gateway or Capella App Services when connectivity is available.
Key properties:
- Embedded — no separate server process; the database is a file on the device
- JSON documents — schema-free; each document is a key-value map
- Collections — logical groupings of documents within a scope (analogous to tables)
- Offline-first — reads and writes work without a network connection
- Sync — bidirectional replication with conflict resolution handled automatically
Database
└── Scope (default: _default)
└── Collection (default: _default)
└── Document (JSON key-value map)
- A database maps to a
.cblite2file on disk. - A scope groups related collections (e.g.
commerce,analytics). - A collection is the unit of query and replication. Use named collections to separate document types instead of using a
typefield. - The default collection (
_default._default) is always present and is what_refers to in SQL++ string queries.
Each document has:
- A document ID — string key, auto-generated UUID if not specified
- A sequence number — monotonically increasing, used for change tracking
- A revision ID — used internally for conflict detection
- A body — arbitrary JSON key-value map (no fixed schema)
Always retrieve before updating. Couchbase Lite uses optimistic concurrency. Saving a MutableDocument derived from a stale read will be rejected if the document was modified concurrently. Always call getDocument / document(id:) immediately before mutating.
| Operation | Notes |
|---|---|
| Create | Use auto-generated ID unless you have a natural key |
| Read | Returns null/nil if not found — always check |
| Update | Retrieve → mutate → save; never construct a MutableDocument from scratch for an existing doc |
| Delete | Leaves a tombstone; document is purged from sync after the tombstone replicates |
| Purge | Removes immediately with no tombstone; use only for local-only cleanup |
A live query re-executes automatically whenever the underlying data changes. The change listener receives a QueryChange object containing the new result set (or an error).
- Register a listener with
addChangeListener— returns aListenerToken - Always call
token.remove()when the listener is no longer needed (e.g. inonStop/deinit) to prevent memory leaks - The listener fires on a background thread; dispatch UI updates to the main thread
| Type | Use case |
|---|---|
| Value index | Speed up WHERE and ORDER BY on specific properties |
| Full-text index | Enable MATCH queries for full-text search |
| Vector index (EE) | Enable approximate nearest-neighbour search |
Create indexes before running queries that need them. Index creation is synchronous and blocks until complete.
Full-text search requires a full-text index on the target property. Use FullTextFunction.match() in QueryBuilder or MATCH() in SQL++ string queries. Supports stemming, stop words, and ranking by relevance.
Blobs store binary data (images, audio, PDFs) attached to a document:
- Stored separately from the document body; the document holds a metadata stub
- Lazy-loaded — blob content is not read from disk until
.content/.contentis accessed - Replicated separately from documents; large blobs do not block document sync
- Content type (MIME type) is required and used by Sync Gateway for filtering
The Replicator syncs one or more collections to a remote endpoint (Sync Gateway or Capella App Services).
Replicator types:
| Type | Direction |
|---|---|
PUSH_AND_PULL |
Bidirectional (default for most apps) |
PUSH |
Local → remote only |
PULL |
Remote → local only |
Continuous vs one-shot:
continuous = true— keeps a persistent connection; reconnects automaticallycontinuous = false— syncs once then stops; use for background fetch
Activity levels:
| Level | Meaning |
|---|---|
CONNECTING |
Establishing connection |
BUSY |
Actively transferring documents |
IDLE |
Connected, no pending changes |
OFFLINE |
No network; will retry |
STOPPED |
Stopped (error or explicit stop) |
Filters:
pushFilter— called for each local document before it is pushed; returnfalseto skippullFilter— called for each remote document before it is saved locally; returnfalseto reject
Always call replicator.stop() and remove the change listener token when the component is destroyed to release the network connection.
| Method | When to use |
|---|---|
BasicAuthenticator |
Username/password (Sync Gateway local users) |
SessionAuthenticator |
Sync Gateway session token (obtained via REST login) |
| Client TLS cert | Mutual TLS with Sync Gateway EE |
Sync Gateway credentials must be retrieved at runtime from the platform secure store, not embedded in source code or BuildConfig/Info.plist constants baked into the binary.
| Platform | API | Dependency |
|---|---|---|
| Android | EncryptedSharedPreferences |
androidx.security:security-crypto |
| iOS / macOS | SecItemCopyMatching |
Security.framework (built-in) |
Android — write credentials (on login):
// androidx.security:security-crypto:1.1.0+
val masterKey = MasterKey.Builder(context)
.setKeyScheme(MasterKey.KeyScheme.AES256_GCM).build()
val prefs = EncryptedSharedPreferences.create(
context, "sg_creds", masterKey,
EncryptedSharedPreferences.PrefKeyEncryptionScheme.AES256_SIV,
EncryptedSharedPreferences.PrefValueEncryptionScheme.AES256_GCM
)
prefs.edit().putString("sg_username", username).putString("sg_password", password).apply()Android — read credentials (before replicator start):
val username = prefs.getString("sg_username", null)!!
val password = prefs.getString("sg_password", null)!!iOS — write credentials (on login):
// Security.framework — no additional dependency
func keychainWrite(key: String, value: String) {
let data = value.data(using: .utf8)!
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: key,
kSecValueData as String: data
]
SecItemDelete(query as CFDictionary) // remove existing before add
SecItemAdd(query as CFDictionary, nil)
}iOS — read credentials (before replicator start):
func keychainRead(key: String) -> String? {
let query: [String: Any] = [
kSecClass as String: kSecClassGenericPassword,
kSecAttrAccount as String: key,
kSecReturnData as String: true
]
var result: AnyObject?
guard SecItemCopyMatching(query as CFDictionary, &result) == errSecSuccess,
let data = result as? Data else { return nil }
return String(data: data, encoding: .utf8)
}Never store credentials in SharedPreferences (Android) or UserDefaults (iOS) — these are not encrypted at rest.
Encrypts the entire .cblite2 file at rest using AES-256. The encryption key must be provided on every open. Losing the key means losing the data — store it in the platform keychain (Android Keystore / iOS Keychain).
| Feature | Community (CE) | Enterprise (EE) |
|---|---|---|
| CRUD, SQL++, live queries | ✓ | ✓ |
| Full-text search | ✓ | ✓ |
| Replication | ✓ | ✓ |
| Database encryption | ✗ | ✓ |
| Vector search | ✗ | ✓ |
| P2P sync (URLEndpointListener) | ✗ | ✓ |
| Delta sync | ✗ | ✓ |