Installation
Gradle (Kotlin DSL)
Add the Supabase Kotlin dependency to your build.gradle.kts:
dependencies {
implementation ( "io.github.jan-tennert.supabase:postgrest-kt:2.0.0" )
implementation ( "io.github.jan-tennert.supabase:realtime-kt:2.0.0" )
implementation ( "io.github.jan-tennert.supabase:storage-kt:2.0.0" )
implementation ( "io.github.jan-tennert.supabase:gotrue-kt:2.0.0" )
implementation ( "io.github.jan-tennert.supabase:functions-kt:2.0.0" )
}
Gradle (Groovy)
dependencies {
implementation 'io.github.jan-tennert.supabase:postgrest-kt:2.0.0'
implementation 'io.github.jan-tennert.supabase:realtime-kt:2.0.0'
implementation 'io.github.jan-tennert.supabase:storage-kt:2.0.0'
implementation 'io.github.jan-tennert.supabase:gotrue-kt:2.0.0'
implementation 'io.github.jan-tennert.supabase:functions-kt:2.0.0'
}
Initializing
Create a Supabase client to interact with your database.
import io.github.jan.supabase.createSupabaseClient
import io.github.jan.supabase.postgrest.Postgrest
import io.github.jan.supabase.gotrue.Auth
import io.github.jan.supabase.storage.Storage
import io.github.jan.supabase.realtime.Realtime
import io.github.jan.supabase.functions.Functions
val supabase = createSupabaseClient (
supabaseUrl = "YOUR_SUPABASE_URL" ,
supabaseKey = "YOUR_SUPABASE_ANON_KEY"
) {
install (Postgrest)
install (Auth)
install (Storage)
install (Realtime)
install (Functions)
}
The unique Supabase URL for your project.
The Supabase anon key for your project.
configuration
SupabaseClientBuilder.() -> Unit
Configuration block for installing plugins. Install the Postgrest plugin for database operations.
Install the Auth plugin for authentication.
Install the Storage plugin for file storage.
Install the Realtime plugin for realtime subscriptions.
Install the Functions plugin for Edge Functions.
Database Operations
Select Data
Query data from your tables.
import io.github.jan.supabase.postgrest.from
import kotlinx.serialization.Serializable
@Serializable
data class Country (
val id: Int ,
val name: String ,
val code: String ,
val capital: String ?
)
val countries = supabase. from ( "countries" )
. select ()
. decodeList < Country >()
The returned rows from the query, deserialized to your data class.
Select with Filters
val country = supabase. from ( "countries" )
. select {
filter {
eq ( "id" , 1 )
}
}
. decodeSingle < Country >()
Select Specific Columns
val countries = supabase. from ( "countries" )
. select (columns = Columns. list ( "name" , "capital" ))
. decodeList < Country >()
Common Filters
// Equal to
val data = supabase. from ( "countries" )
. select {
filter {
eq ( "name" , "Albania" )
}
}
. decodeList < Country >()
// Not equal to
val data = supabase. from ( "countries" )
. select {
filter {
neq ( "name" , "Albania" )
}
}
. decodeList < Country >()
// Greater than
val data = supabase. from ( "countries" )
. select {
filter {
gt ( "population" , 1000000 )
}
}
. decodeList < Country >()
// Less than
val data = supabase. from ( "countries" )
. select {
filter {
lt ( "population" , 1000000 )
}
}
. decodeList < Country >()
// Like (pattern matching)
val data = supabase. from ( "countries" )
. select {
filter {
ilike ( "name" , "%Alba%" )
}
}
. decodeList < Country >()
// In list
val data = supabase. from ( "countries" )
. select {
filter {
isIn ( "name" , listOf ( "Albania" , "Algeria" ))
}
}
. decodeList < Country >()
Insert Data
Insert rows into your tables.
@Serializable
data class NewCountry (
val name: String ,
val code: String
)
val newCountry = NewCountry (name = "Denmark" , code = "DK" )
val result = supabase. from ( "countries" )
. insert (newCountry) {
select ()
}
. decodeSingle < Country >()
Insert Multiple Rows
val countries = listOf (
NewCountry (name = "Denmark" , code = "DK" ),
NewCountry (name = "Norway" , code = "NO" )
)
val result = supabase. from ( "countries" )
. insert (countries) {
select ()
}
. decodeList < Country >()
Update Data
Update existing rows in your tables.
@Serializable
data class CountryUpdate (
val name: String
)
val update = CountryUpdate (name = "Australia" )
val result = supabase. from ( "countries" )
. update (update) {
filter {
eq ( "id" , 1 )
}
select ()
}
. decodeList < Country >()
Upsert Data
Insert or update rows based on unique constraints.
val country = Country (
id = 1 ,
name = "Australia" ,
code = "AU" ,
capital = "Canberra"
)
val result = supabase. from ( "countries" )
. upsert (country) {
select ()
}
. decodeSingle < Country >()
Delete Data
Delete rows from your tables.
supabase. from ( "countries" )
. delete {
filter {
eq ( "id" , 1 )
}
}
Authentication
Sign Up
Create a new user account.
import io.github.jan.supabase.gotrue.auth
import io.github.jan.supabase.gotrue.providers.builtin.Email
val result = supabase.auth. signUpWith (Email) {
email = "[email protected] "
password = "example-password"
}
The user’s email address.
Additional user metadata.
A URL to redirect to after signup.
Sign In
Sign in an existing user.
val result = supabase.auth. signInWith (Email) {
email = "[email protected] "
password = "example-password"
}
Sign Out
Sign out the current user.
Get Session
Get the current session.
val session = supabase.auth. currentSessionOrNull ()
The current session object or null if no active session.
Get User
Get the current user.
val user = supabase.auth. currentUserOrNull ()
The current user object or null if not authenticated.
Auth State Changes
Listen to authentication state changes.
import io.github.jan.supabase.gotrue.SessionStatus
supabase.auth.sessionStatus. collect { status ->
when (status) {
is SessionStatus.Authenticated -> {
println ( "User signed in: ${ status.session.user?.email } " )
}
is SessionStatus.NotAuthenticated -> {
println ( "User signed out" )
}
else -> {}
}
}
Storage
Upload File
Upload a file to a storage bucket.
import io.github.jan.supabase.storage.storage
import io.github.jan.supabase.storage.upload
val fileData = File ( "path/to/file" ). readBytes ()
val result = supabase.storage
. from ( "avatars" )
. upload ( "public/avatar1.png" , fileData) {
contentType = "image/png"
}
The file path including the file name.
When true, overwrites existing file with the same path.
Download File
Download a file from storage.
import io.github.jan.supabase.storage.download
val data = supabase.storage
. from ( "avatars" )
. download ( "public/avatar1.png" )
The file path to download.
List Files
List all files in a bucket.
val files = supabase.storage
. from ( "avatars" )
. list ( "public" )
Delete Files
Delete files from storage.
supabase.storage
. from ( "avatars" )
. delete ( listOf ( "public/avatar1.png" , "public/avatar2.png" ))
Get Public URL
Get the public URL for a file.
import io.github.jan.supabase.storage.publicUrl
val url = supabase.storage
. from ( "avatars" )
. publicUrl ( "public/avatar1.png" )
println (url)
Realtime
Subscribe to Changes
Listen to database changes in realtime.
import io.github.jan.supabase.realtime.channel
import io.github.jan.supabase.realtime.postgresChangeFlow
import io.github.jan.supabase.realtime.PostgresAction
val channel = supabase. channel ( "db-changes" )
val changeFlow = channel. postgresChangeFlow < PostgresAction >(schema = "public" ) {
table = "countries"
}
changeFlow. collect { action ->
when (action) {
is PostgresAction.Insert -> println ( "New country: ${ action.record } " )
is PostgresAction.Update -> println ( "Updated country: ${ action.record } " )
is PostgresAction.Delete -> println ( "Deleted country" )
}
}
channel. subscribe ()
The database schema to listen to.
Unsubscribe
Stop listening to changes.
supabase. removeChannel (channel)
Edge Functions
Invoke Function
Invoke a Supabase Edge Function.
import io.github.jan.supabase.functions.functions
import io.github.jan.supabase.functions.invoke
import kotlinx.serialization.Serializable
@Serializable
data class FunctionPayload ( val name: String )
@Serializable
data class FunctionResponse ( val message: String )
val response = supabase.functions. invoke < FunctionResponse >(
function = "hello-world" ,
body = FunctionPayload (name = "Functions" )
)
The name of the Edge Function to invoke.
The request body to send to the function.
Custom headers to send with the request.
method
HttpMethod
default: "HttpMethod.Post"
HTTP method to use.
The response data from the function, deserialized to your data class.
Error Handling
Handle errors using try-catch blocks:
try {
val countries = supabase. from ( "countries" )
. select ()
. decodeList < Country >()
println ( "Countries: $countries " )
} catch (e: RestException ) {
println ( "Database error: ${ e.message } " )
} catch (e: Exception ) {
println ( "Unexpected error: ${ e.message } " )
}
Use Supabase with Compose Multiplatform:
import androidx.compose.runtime. *
import kotlinx.coroutines.launch
@Composable
fun CountriesScreen () {
var countries by remember { mutableStateOf < List < Country >>( emptyList ()) }
val scope = rememberCoroutineScope ()
LaunchedEffect (Unit) {
scope. launch {
try {
countries = supabase. from ( "countries" )
. select ()
. decodeList < Country >()
} catch (e: Exception ) {
println ( "Error loading countries: ${ e.message } " )
}
}
}
LazyColumn {
items (countries) { country ->
Text (country.name)
}
}
}
Additional Resources
GitHub Repository View the source code and contribute
Maven Central View package details and versions