
Offline-first sync library for Kotlin Multiplatform — outbox, push/pull, conflicts, and Compose helpers for Android, iOS, and desktop.
Offline-first sync for Kotlin Multiplatform — Android, iOS, JVM desktop, and native macOS.
v2.0.0 on Maven Central · Release notes
Your app keeps its own database (Room on Android, or any store you choose). SyncForge owns a separate outbox and conflict store, then push/pulls over a pluggable transport. Local writes are instant; sync survives offline use and app restarts.
./gradlew :mock-server:run # Terminal 1
./gradlew :sample:installDebug # Terminal 2 — emulator uses http://10.0.2.2:8080Tap Sync in the sample app, trigger a conflict, or clear local data and pull from the server. Debug builds show an SF overlay for outbox and sync health.
Offline-first — Users edit locally; mutations queue in a durable outbox until the network returns.
Your data stays yours — Entity tables live in your Room DB or custom EntityStore. SyncForge does not replace your schema.
Conflict-aware — Per-entity strategies: last-write-wins, user resolution, field merge, gitLike three-way merge, CRDT fields.
Pluggable backend — Default REST/Ktor transport, or GraphQL, Supabase, Firebase, and custom SyncTransport adapters.
Optional sync — Ship offline-only, self-host a backend, or point at any server implementing the push/pull contract.
Import the version catalog once (2.0.0 pins every artifact and the Gradle plugin):
// settings.gradle.kts
dependencyResolutionManagement {
versionCatalogs {
create("syncforge") {
from("studio.syncforge:syncforge-catalog:2.0.0")
}
}
}// app/build.gradle.kts
plugins {
alias(syncforge.plugins.syncforge.android)
}
dependencies {
implementation(syncforge.core)
}// Application
syncManager = SyncForge.android(this) {
baseUrl("https://api.example.com")
registry(SyncForgeHandlers.registry(taskDao))
schedulePeriodicSyncOnStart()
}
// Repository
syncManager.enqueueChange(Change.create("tasks", task))
syncManager.sync()Full walkthrough (~10 min): Getting Started
| Platform | Entry point | Setup guide | Sample |
|---|---|---|---|
| Android | SyncForge.android { } |
Android setup | :sample |
| iOS | SyncForge.ios { } |
iOS setup | :ios-sample |
| JVM desktop | SyncForge.desktop { } |
Desktop setup | :sample-desktop |
| macOS native | SyncForge.macos { } |
Desktop setup | — |
| Browser |
SyncForge.web { } (experimental)
|
Web setup | :sample-web |
Gradle snippets, DSL options, and platform-specific wiring are in each setup guide — not duplicated here.
| All features + samples | Feature catalog |
| Copy-paste recipes | Recipes |
| API reference | Modules |
| Backend contract | REST API |
| Conflicts | Conflict resolution |
| Everything else | docs/README.md |
| Module | What it proves |
|---|---|
:sample |
Multi-entity sync, gitLike conflicts, debug overlay, Compose UI |
:mock-server |
Reference backend + conflict simulation endpoints |
:backend-starter-spring |
Spring Boot + JDBC store |
Want to contribute or run the repo locally? See CONTRIBUTING.md.
git clone https://github.com/Arsenoal/syncforge.git
cd syncforge
./gradlew verifyReleaseSignOffOffline-first sync for Kotlin Multiplatform — Android, iOS, JVM desktop, and native macOS.
v2.0.0 on Maven Central · Release notes
Your app keeps its own database (Room on Android, or any store you choose). SyncForge owns a separate outbox and conflict store, then push/pulls over a pluggable transport. Local writes are instant; sync survives offline use and app restarts.
./gradlew :mock-server:run # Terminal 1
./gradlew :sample:installDebug # Terminal 2 — emulator uses http://10.0.2.2:8080Tap Sync in the sample app, trigger a conflict, or clear local data and pull from the server. Debug builds show an SF overlay for outbox and sync health.
Offline-first — Users edit locally; mutations queue in a durable outbox until the network returns.
Your data stays yours — Entity tables live in your Room DB or custom EntityStore. SyncForge does not replace your schema.
Conflict-aware — Per-entity strategies: last-write-wins, user resolution, field merge, gitLike three-way merge, CRDT fields.
Pluggable backend — Default REST/Ktor transport, or GraphQL, Supabase, Firebase, and custom SyncTransport adapters.
Optional sync — Ship offline-only, self-host a backend, or point at any server implementing the push/pull contract.
Import the version catalog once (2.0.0 pins every artifact and the Gradle plugin):
// settings.gradle.kts
dependencyResolutionManagement {
versionCatalogs {
create("syncforge") {
from("studio.syncforge:syncforge-catalog:2.0.0")
}
}
}// app/build.gradle.kts
plugins {
alias(syncforge.plugins.syncforge.android)
}
dependencies {
implementation(syncforge.core)
}// Application
syncManager = SyncForge.android(this) {
baseUrl("https://api.example.com")
registry(SyncForgeHandlers.registry(taskDao))
schedulePeriodicSyncOnStart()
}
// Repository
syncManager.enqueueChange(Change.create("tasks", task))
syncManager.sync()Full walkthrough (~10 min): Getting Started
| Platform | Entry point | Setup guide | Sample |
|---|---|---|---|
| Android | SyncForge.android { } |
Android setup | :sample |
| iOS | SyncForge.ios { } |
iOS setup | :ios-sample |
| JVM desktop | SyncForge.desktop { } |
Desktop setup | :sample-desktop |
| macOS native | SyncForge.macos { } |
Desktop setup | — |
| Browser |
SyncForge.web { } (experimental)
|
Web setup | :sample-web |
Gradle snippets, DSL options, and platform-specific wiring are in each setup guide — not duplicated here.
| All features + samples | Feature catalog |
| Copy-paste recipes | Recipes |
| API reference | Modules |
| Backend contract | REST API |
| Conflicts | Conflict resolution |
| Everything else | docs/README.md |
| Module | What it proves |
|---|---|
:sample |
Multi-entity sync, gitLike conflicts, debug overlay, Compose UI |
:mock-server |
Reference backend + conflict simulation endpoints |
:backend-starter-spring |
Spring Boot + JDBC store |
Want to contribute or run the repo locally? See CONTRIBUTING.md.
git clone https://github.com/Arsenoal/syncforge.git
cd syncforge
./gradlew verifyReleaseSignOff