Platform setup

Table of contents
  1. Android
    1. Where to instantiate
    2. Database file
  2. JVM
    1. In-memory (default)
    2. File-backed
  3. Threading
  4. iOS / Native
  5. Next

Sqkon ships a single Maven artifact with platform-specific Sqkon(...) factory functions. This page covers the construction details for each target and the threading rules that apply everywhere.

Android

The Android factory needs a Context and a CoroutineScope:

fun Sqkon(
    context: Context,
    scope: CoroutineScope,
    json: Json = SqkonJson { },
    dbFileName: String? = "sqkon.db",
    config: KeyValueStorage.Config = KeyValueStorage.Config(),
): Sqkon

Where to instantiate

Treat the Sqkon instance like a database connection pool: create one per database for the lifetime of your process. The natural place is your Application subclass:

class MyApplication : Application() {
    private val appScope = CoroutineScope(SupervisorJob() + Dispatchers.Default)

    val sqkon: Sqkon by lazy {
        Sqkon(context = this, scope = appScope)
    }
}

Inject sqkon (or specific KeyValueStorage<T> instances) into your DI graph from there.

Database file

By default Sqkon writes to sqkon.db inside your app’s standard database directory (the same place Room stores its databases). To pick a different file name, pass dbFileName:

Sqkon(context = this, scope = appScope, dbFileName = "my-cache.db")

To run in-memory — useful for instrumented tests or transient caches that should not survive a process restart — pass null:

Sqkon(context = this, scope = appScope, dbFileName = null)

An older overload accepted inMemory: Boolean and is now deprecated. Migrate to dbFileName = null (or omit the parameter to use the default "sqkon.db"); the deprecated overload simply forwards to the new one.

JVM

The JVM factory takes a CoroutineScope and a SqkonDatabaseType:

fun Sqkon(
    scope: CoroutineScope,
    json: Json = SqkonJson { },
    type: SqkonDatabaseType = SqkonDatabaseType.Memory,
    config: KeyValueStorage.Config = KeyValueStorage.Config(),
    driverConfig: SqkonDriverConfig = SqkonDriverConfig(),
): Sqkon

In-memory (default)

The default is SqkonDatabaseType.Memory, which is ideal for unit tests:

val sqkon = Sqkon(scope = scope) // in-memory by default

File-backed

For a persistent JVM database, point at a file:

import com.mercury.sqkon.db.SqkonDatabaseType

val sqkon = Sqkon(
    scope = appScope,
    type = SqkonDatabaseType.FileBacked("data/sqkon.db"),
)

The path is resolved relative to the JVM’s working directory — pass an absolute path if that is ambiguous in your environment.

Threading

Sqkon manages its own dispatchers internally. You don’t need to wrap calls in withContext(Dispatchers.IO) — the library does it for you.

Internally:

  • Reads run on a Dispatchers.IO-based dispatcher with limited parallelism = 4, matching SQLite’s default WAL connection pool size.
  • Writes run on a Dispatchers.IO-based dispatcher with limited parallelism = 1 (SQLite allows only one writer at a time).

This is configured in Sqkon.kt and the platform SqkonDatabaseDriver files.

Sqkon’s SQLite driver is synchronous by design; it serializes work through its own dispatchers (one writer, a small reader pool) rather than an async driver, which doesn’t play well with multithreaded hosts.

The CoroutineScope you pass to Sqkon(...) is used as the parent of the internal reactive query coroutines. Cancel that scope (typically only in tests or when shutting down a worker process) to release database resources.

iOS / Native

Not usable on iOS yet. The iOS source set is scaffolded and compiles, but the platform DriverFactory.createDriver() is still a TODO stub — there is no public Sqkon(...) factory for iOS. Now that Sqkon runs on androidx.sqlite (which ships a KMP/native BundledSQLiteDriver), the only remaining work is wiring that actual; the old eygraber JVM/Android-only driver is gone.

If iOS support matters to you, please open or upvote an issue on the GitHub repo.

Next