keep your client up even when the network is down
Your users don't live in a world of perfect connectivity. But most apps are built as if they do.
Users tap a button and see a loading spinner... then an error. They're in an elevator, on a subway, in a rural area. The app is useless.
Every new feature needs its own connectivity checks, local caching, retry logic, and queue management. You've written this code three times already.
Two edits happen at once — one offline, one on the server. Without proper conflict resolution, someone's work gets silently overwritten.
This demo simulates how an app using buoyient handles connectivity changes. Toggle the network and add some todos.
Toggle offline, add items, then toggle back online. Watch the pending items sync up automatically.
Here's what it takes to create an offline-capable todo item, with and without buoyient.
suspend fun createTodo(title: String) {
val todo = Todo(title = title)
// Save locally first
db.todoDao().insert(todo)
if (isNetworkAvailable()) {
try {
val response = api.post("/todos", todo)
if (response.isSuccessful) {
val server = response.body()
db.todoDao().update(
todo.copy(
serverId = server.id,
version = server.version,
syncStatus = "synced"
)
)
} else {
enqueueRetry(todo)
}
} catch (e: IOException) {
enqueueRetry(todo)
}
} else {
enqueueRetry(todo)
}
}
// Plus you still need:
// - RetryQueue with SQLite persistence
// - WorkManager job to drain the queue
// - Conflict detection on sync-down
// - Idempotency key management
// - Placeholder ID resolution
// - ConnectivityManager listener
// - Error handling per retry attempt
// ... for every single entity type
suspend fun createTodo(title: String):
SyncableObjectServiceResponse<Todo> {
val todo = Todo(title = title)
return create(
data = todo,
requestTag = TodoRequestTag.CREATE,
request = CreateRequestBuilder { data, key, _, _ ->
HttpRequest(
method = HttpRequest.HttpMethod.POST,
endpointUrl = "https://api.example.com/todos",
requestBody = buildJsonObject {
put("idempotency_key", key)
put("title", data.title)
put("reference_id", data.clientId)
},
)
},
unpackSyncData = unpacker,
)
}
Offline queueing, retries, conflict detection, sync-down, placeholder resolution, and idempotency are all handled automatically by the engine.
buoyient handles the hard parts so you can focus on your domain logic.
Operations succeed immediately, regardless of connectivity. Data is persisted locally and synced when the network returns.
Periodic sync-down pulls server changes. Sync-up pushes local changes. Both directions handled automatically.
Field-level conflict detection compares base, local, and server states. Pluggable merge policies let you decide how to resolve.
Pending requests are saved to SQLite. They survive app restarts and process in order with automatic retries.
Reference objects that haven't synced yet with {serverId} placeholders. Resolved automatically at sync time.
Built for AI-assisted integration. Includes detailed instruction files, step-by-step guides, and skills for Claude, Copilot, and Cursor.