A Kotlin Multiplatform SDK for Appwrite — built from scratch with type safety, coroutines, and multiplatform support at its core.
Targets: Android, iOS, JVM
The official Appwrite Android SDK is tightly coupled to Android (OkHttp, Gson, SharedPreferences). This SDK is designed for Kotlin Multiplatform from day one:
- Errors as values —
AppwriteResult<T>instead of thrown exceptions - Type-safe IDs —
DatabaseId,CollectionId,FileId— no more string mix-ups - Query DSL —
where("age" greaterThan 18)instead of raw strings - Flow-based realtime — auto-reconnect, exponential backoff, coroutine-scoped
- Chunked uploads as Flow —
Flow<UploadState>with progress tracking - Modular — pull in only what you need
dependencies {
implementation("io.github.androidpoet:appwrite-client:<version>")
implementation("io.github.androidpoet:appwrite-auth:<version>")
implementation("io.github.androidpoet:appwrite-database:<version>")
implementation("io.github.androidpoet:appwrite-storage:<version>")
implementation("io.github.androidpoet:appwrite-realtime:<version>")
implementation("io.github.androidpoet:appwrite-teams:<version>")
implementation("io.github.androidpoet:appwrite-functions:<version>")
implementation("io.github.androidpoet:appwrite-locale:<version>")
implementation("io.github.androidpoet:appwrite-avatars:<version>")
}val appwrite =Appwrite("your-project-id") {
endpoint ="https://cloud.appwrite.io/v1"
}
appwrite.sessionStore =SessionStore()importio.appwrite.auth.authval user = appwrite.auth.signUp(
email ="user@example.com",
password ="password123",
name ="Jane Doe",
)
when (val result = appwrite.auth.signInWithEmail("user@example.com", "password123")) {
isAppwriteResult.Success->println("Session: ${result.data.id}")
isAppwriteResult.Failure->println("Error: ${result.error.message}")
}
appwrite.auth.mfa.enable()
appwrite.auth.mfa.createAuthenticator(AuthenticationFactor.Totp)
appwrite.auth.mfa.verifyAuthenticator(AuthenticationFactor.Totp, otp ="123456")
appwrite.auth.signOut()importio.appwrite.database.databasesval db = appwrite.databases
val users = db[DatabaseId("main")][CollectionId("users")]
users.create(
data =mapOf("name" to "Jane", "age" to 28, "status" to "active"),
)
val result = users.list {
where("age" greaterThan 18)
where("status" equal "active")
orderBy("name")
limit(25)
}
users.update(
documentId =DocumentId("abc123"),
data =mapOf("status" to "inactive"),
)importio.appwrite.storage.storageval file =InputFile.fromBytes(imageBytes, "photo.jpg", "image/jpeg")
appwrite.storage.upload(BucketId("photos"), FileId.unique(), file)
.collect { state ->when (state) {
isUploadState.Progress->println("${state.chunksUploaded}/${state.chunksTotal}")
isUploadState.Complete->println("Uploaded: ${state.file.id}")
isUploadState.Failed->println("Error: ${state.error.message}")
}
}
val bytes = appwrite.storage.download(BucketId("photos"), FileId("abc123"))
val thumbnail = appwrite.storage.preview(BucketId("photos"), FileId("abc123")) {
width =200
height =200
gravity =ImageGravity.Center
quality =80
}importio.appwrite.realtime.realtime
appwrite.realtime
.documents(DatabaseId("main"), CollectionId("messages"))
.onEach { event -> updateUI(event.payload) }
.launchIn(viewModelScope) // auto-cleanup on scope cancellation
appwrite.realtime.account()
.collect { event -> handleAccountEvent(event) }importio.appwrite.teams.teams
appwrite.teams.create(TeamId.unique(), name ="Engineering")
appwrite.teams.createMembership(
teamId =TeamId("eng-team"),
roles =listOf("developer"),
email ="dev@example.com",
)importio.appwrite.functions.functionsval execution = appwrite.functions.createExecution(
functionId =FunctionId("send-welcome-email"),
body ="""{"userId": "abc123"}""",
)┌─────────────────────────────────────┐
│ Public API (what devs touch) │ DSL builders, typed IDs, Flows
├─────────────────────────────────────┤
│ Domain (business logic) │ Session management, query builder,
│ │ chunked upload orchestration
├─────────────────────────────────────┤
│ Protocol (Appwrite specifics) │ Header injection, error mapping,
│ │ response deserialization
├─────────────────────────────────────┤
│ Transport (HTTP/WS engine) │ Ktor client, expect/actual
└─────────────────────────────────────┘
| Module | Description |
|---|---|
appwrite-core | Models, typed IDs, AppwriteResult, query DSL |
appwrite-client | Appwrite entry point, Ktor transport, session persistence |
appwrite-auth | Authentication, sessions, MFA, verification, recovery |
appwrite-database | Document CRUD with scoped navigation, atomic ops |
appwrite-storage | File upload (chunked with Flow), download, preview |
appwrite-realtime | WebSocket subscriptions as Kotlin Flows |
appwrite-teams | Team and membership management |
appwrite-functions | Serverless function execution |
appwrite-locale | Languages, countries, currencies, timezones |
appwrite-avatars | Generated avatars, flags, QR codes |
Errors as values, not exceptions
sealedinterfaceAppwriteResult<outT> {
data classSuccess<T>(valdata:T) : AppwriteResult<T>
data classFailure(valerror:AppwriteError) : AppwriteResult<Nothing>
}Value class IDs prevent string mix-ups
fungetDocument(databaseId:DatabaseId, collectionId:CollectionId, documentId:DocumentId)Session persistence is opt-in and platform-aware
appwrite.sessionStore =SessionStore()| Concern | Library |
|---|---|
| HTTP | Ktor |
| Serialization | kotlinx.serialization |
| Async | Kotlin Coroutines |
| Date/Time | kotlinx-datetime |
- Appwrite Server: 1.8.x+
- Kotlin: 2.1+
- Platforms: Android, iOS (arm64, x64, simulator), JVM
- Fork the repo
- Create a feature branch (
git checkout -b feature/amazing-thing) - Make your changes
- Run tests:
./gradlew jvmTest - Open a PR
Support it by joining stargazers for this repository. ⭐
Also, follow me on GitHub for my next creations! 🤩
