Skip to content

Client SDK Overview

Native SDKs for iOS, Android, and React Native. These are not JavaScript wrappers — they are native implementations using platform-standard database libraries (GRDB for Swift, Room/SQLiteOpenHelper for Kotlin). Each SDK embeds a full sync engine that handles registration, schema management, CDC-based change tracking, push/pull, conflict resolution, and snapshot recovery.

SDKPlatformDatabaseStatus
SwiftiOS / macOSGRDB (SQLite)Available
KotlinAndroidSQLiteOpenHelperAvailable
React NativeiOS + AndroidSwift + Kotlin bridgeAvailable

The SDK stack has two layers:

  • Layer 1 (Native): Swift wraps GRDB, Kotlin wraps Android SQLiteOpenHelper. Each contains a full sync engine — schema manager, change tracker, push/pull processors, HTTP client, and retry logic.
  • Layer 2 (React Native): A TurboModule bridge wraps both native SDKs. SQL strings go down, JSON rows come back up. React hooks provide reactive bindings on top.
graph TB
    subgraph "React Native"
        JS[JavaScript / TypeScript]
        Bridge[TurboModule Bridge]
    end
    subgraph "Native"
        Swift[Swift SDK
GRDB + SQLite] Kotlin[Kotlin SDK
SQLiteOpenHelper + SQLite] end JS --> Bridge Bridge --> Swift Bridge --> Kotlin

All SDKs expose the same logical API. Method names and signatures are consistent across platforms, differing only in language idioms (async/await in Swift, suspend in Kotlin, Promise in TypeScript).

MethodDescription
query(sql, params)Execute a SELECT, return all matching rows
queryOne(sql, params)Execute a SELECT, return the first row or null
execute(sql, params)Execute an INSERT/UPDATE/DELETE, return rows affected
executeBatch(statements)Execute multiple statements in a single transaction
MethodDescription
readTransaction(block)Execute a block inside a read transaction
writeTransaction(block)Execute a block inside a write transaction
MethodDescription
createTable(name, columns, options?)Create a local-only table
alterTable(name, addColumns)Add columns to an existing table
createIndex(table, columns, unique?)Create an index on a table
MethodDescription
onChange(tables, callback)Notify when any of the listed tables change; returns a cancellable
watch(sql, params, tables, callback)Re-execute the query whenever the listed tables change; returns a cancellable
MethodDescription
start()Register with the server, fetch schema, begin the sync loop
stop()Stop the sync loop
syncNow()Trigger an immediate sync cycle
MethodDescription
onStatusChange(callback)Observe sync status transitions (idle, syncing, error, stopped)
onConflict(callback)Receive conflict events with client and server data
onSnapshotRequired(handler)Prompt the user when a full resync is required

SQLite triggers automatically track all writes to synced tables. There is no special write API — standard SQL INSERT, UPDATE, and DELETE statements work. The CDC system intercepts changes transparently.

graph LR
    A[client.execute] --> B[SQLite Write]
    B --> C[CDC Trigger]
    C --> D[_synchro_pending_changes]
    D --> E[Push to Server]
    E --> F[Server Accepts]
    F --> G[Drain from Queue]
TriggerFires OnRecords As
AFTER INSERTAny INSERT into a synced tablecreate operation
AFTER UPDATEAny UPDATE on a synced tableupdate operation (or delete if deleted_at becomes non-null)
BEFORE DELETEAny DELETE on a synced tableConverts hard delete to soft delete (sets deleted_at, cancels the DELETE)

The server schema uses PostgreSQL types. Each column is assigned a logical type that determines how values are stored in SQLite and serialized over the wire.

Logical TypeSQLite TypeExample
stringTEXTUUID, varchar, enum
intINTEGERinteger, smallint
int64INTEGERbigint
floatREALreal, double precision
booleanINTEGER0 / 1
datetimeTEXTISO 8601
dateTEXTYYYY-MM-DD
timeTEXTHH:MM:SS
jsonTEXTJSON string
bytesBLOBbytea

All SDKs share the same configuration parameters and defaults.

ParameterTypeDefaultConstraint
dbPathStringRequired
serverURLString / URLRequired
authProviderAsync functionRequiredReturns JWT token
clientIDStringRequiredUnique device identifier
platformString"ios" / "android"
appVersionStringRequiredSemantic version
syncIntervalSeconds30
pushDebounceSeconds0.5
maxRetryAttemptsInt5
pullPageSizeInt1001—1000
pushBatchSizeInt1001—1000
snapshotPageSizeInt1001—1000