Skip to Content
QuickstartsAndroid (Kotlin)

Android (Kotlin)

Build and query a ZXCV database from an Android app, then ship it to the edge. You’ll end with a screen that reads live data.

AI Assistance
Help me connect ZXCV to my Android app. Do the following:
1. Add the io.zxcv:zxcv-kotlin dependency to app/build.gradle.kts.
2. Initialize a ZXCVClient in my Application subclass with my project ref + anon key (from Settings → API), reading the key from a BuildConfig field fed by local.properties rather than hard-coding it.
3. Fetch rows from a "todos" table in a viewModelScope coroutine and render them with a Jetpack Compose LazyColumn.
4. Keep the anon key on the client — authorization is enforced server-side by my policies.
Ask me for my project ref and anon key if I haven't given them.

Create a project

In the dashboard  click Start building, or run zxcv from your terminal. Open Settings → API and copy your project ref and anon key — the anon key is public and safe to ship, because access is enforced server-side by your authorization rules.

Create a table

In the SQL editor, create a todos table with a couple of rows:

create table todos ( id bigint generated always as identity primary key, title text not null, is_complete boolean not null default false ); insert into todos (title) values ('Read the docs'), ('Ship an app');

Install the SDK

Add the io.zxcv:zxcv-kotlin dependency to your app-module build.gradle.kts:

app/build.gradle.kts
dependencies { implementation("io.zxcv:zxcv-kotlin:1.0.0") }

Then sync Gradle:

./gradlew build

Initialize the client

Create the client once in your Application subclass so it lives for the whole process, and register it in your AndroidManifest.xml. The anon key is safe to ship in client code:

App.kt
import android.app.Application import io.zxcv.ZXCVClient class App : Application() { override fun onCreate() { super.onCreate() zxcv = ZXCVClient(project = "acme-store", anonKey = "your-anon-key") } companion object { lateinit var zxcv: ZXCVClient private set } }

Register the class in AndroidManifest.xml with <application android:name=".App" ... >. For real projects, keep your keys out of source with a BuildConfig field fed from local.properties rather than hard-coding them.

Fetch and render

Fetch the rows in a coroutine off viewModelScope, expose them as state, and render them with a Jetpack Compose LazyColumn:

TodosScreen.kt
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.items import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope import androidx.lifecycle.compose.collectAsStateWithLifecycle import kotlinx.coroutines.flow.MutableStateFlow import kotlinx.coroutines.flow.asStateFlow import kotlinx.coroutines.launch data class Todo(val id: Long, val title: String, val isComplete: Boolean) class TodosViewModel : ViewModel() { private val _todos = MutableStateFlow<List<Todo>>(emptyList()) val todos = _todos.asStateFlow() init { viewModelScope.launch { _todos.value = App.zxcv .from("todos") .select("id, title, is_complete") .order("id") } } } @Composable fun TodosScreen(viewModel: TodosViewModel) { val todos by viewModel.todos.collectAsStateWithLifecycle() LazyColumn { items(todos) { todo -> Text(text = todo.title) } } }

Deploy

Ship your project to the global edge from your terminal:

npm i -g zxcv zxcv link acme-store zxcv deploy --prod

Every push gets a preview URL; --prod promotes to your domain. See Deploy for custom domains and canaries.

Next steps