supabase-kt
supabase-kt copied to clipboard
[Feature request]: Add support for offline data persistence
General Info
- [X] I installed the latest version of Supabase Kt
- [X] I checked for similar feature requests
Feature request
As requested by a bunch of developers:
In many cases such as Mobile Apps, you will want to allow the user to use your app while having no connection to Supabase. For that, you currently have to implement data caching yourself. supabase-kt should support this, but I'm not completely sure which way I'd go to support:
- Postgrest
- Realtime
- (Storage)
If data gets removed/modified locally while offline, syncing should also be done automatically when back online.
Firebase/Firestore does support this.
Proposal:
For Postgrest: The idea would be to have a local SQLite database via SQLDelight or SQLite and cache the data when any postgrest request is made.
- Only requested data gets saved, so no additional requests are being made.
- Filter support can probably also be realized by converting the rest query to an SQL query.
- For inserting entries to the local db while offline, we can just save the postgrest request 1:1 and when back online, insert them all at once in one request
- For modifying and deleting entries from the local db while offline, we probably have to make separate requests once the device is back online
With this approach, we have to device how we get the table schemas, which obviously should be created before any caching is done.
For Realtime:
If the device looses connection, the device listens to the local DB for changes*
* Maybe only for the high-level functions such as selectAsFlow
I put Storage in parenthesis, because other libraries such as Coil basically do that for us.
Usecase
No response
@grdsdev @dshukertjr, would love to hear your thoughts on this!
Are you thinking of creating a separate library that adds offline capabilities, or building offline support right into supabase-kt? If it's a library that users can optionally add to make it local-first, then maybe it's less of an issue, but there is always the risk of Supabase bringing a proper local-first solution and having to migrate to the solution.
We are constantly moving towards adding local-first to Postgres, and ultimately Supabase, and we want to make sure that we play the long game, and not come up with a quick solution that will half-solve the problem. Our most recent effort here Postgres has a lot of components to it, and there is a lot that you cannot do with just a sqlite database, such as handling triggers or Postgres functions.
I'm sure there are plenty of libraries that support local-first apps, and perhaps a better solution might be to build an adaptor of Supabase for them. Here is what I did with a community member for Flutter recently: https://supabase.com/blog/offline-first-flutter-apps . I know Powersync also supports Kotlin, although I have never tried it myself. https://github.com/powersync-ja/powersync-kotlin
With that being said, supabase-kt is currently a community library, so there is a bit more room to explore new things in general.
Are you thinking of creating a separate library that adds offline capabilities, or building offline support right into supabase-kt? If it's a library that users can optionally add to make it local-first
Well, I've heard from a few people that data persistence similar to Firestore would be nice (which you can basically just enable), but ideally that would definitely be a separate library, even though we need to make some internal changes to the Kotlin library.
We are constantly moving towards adding local-first to Postgres, and ultimately Supabase, and we want to make sure that we play the long game, and not come up with a quick solution that will half-solve the problem. Our most recent effort here Postgres has a lot of components to it, and there is a lot that you cannot do with just a sqlite database, such as handling triggers or Postgres functions.
Yes, that's what I thought too. A SQLite DB is the simplest solution, but it lacks some of the features supported by Postgres.
I'm sure there are plenty of libraries that support local-first apps, and perhaps a better solution might be to build an adaptor of Supabase for them. Here is what I did with a community member for Flutter recently: https://supabase.com/blog/offline-first-flutter-apps . I know Powersync also supports Kotlin, although I have never tried it myself. https://github.com/powersync-ja/powersync-kotlin
The selection for such libraries especially with support for Kotlin Multiplatform is not very large, the current widespread solution is to use SQLDelight or Room (as recommended in the Android docs), but you still have to implement the whole caching & syncing part yourself. But I haven't looked into Powersync yet.
Maybe a good short-term solution would be to make a sample similar of what you did with Flutter on how to make an offline-first Android/Kotlin MP application.
I was also thinking of that, because sometime we need to cache edge function or supabase database table response. I am thinking to add ktor caching same as retrofit http caching of any api response with condition.
Hey y'all! 👋 We've recently been exploring some offline work using supabase-kt (really appreciate all the hard work @jan-tennert + community) and wanted to ask some questions / share some thoughts, starting with some context:
1. Why We Are Exploring This
Our apps (Android + iOS, Kotlin Multiplatform shared logic) operate in environments where our users frequently lose connectivity.
We began experimenting with a wrapper-based offline layer for:
- PostgREST (caching SELECT responses under stable signatures)
- Storage (caching downloaded files to disk)
2. Goals for Offline-First Support
What we need offline:
- Read access to previously-fetched rows
- Read access to previously-downloaded files
- Ability to queue writes offline (insert/update/delete)
- Automatic replay of queued operations when back online
3. PostgREST Offline Thoughts
Our current wrapper caches SELECT results using:
(CacheKey = table + filters + order + range)
val offline = createSupabaseOfflineClient(context, supabase)
val assets = offline["assets"] // OfflinePostgrestQueryBuilder
// Server-first, cached transparently, offline fallback
val result = assets.selectAll(
orderBy = "updated_at",
ascending = false,
limit = 50
)
val list = result.decodeList<Asset>()
Benefits:
- Very small and predictable footprint
- No extra queries
- Replay is trivial: just return cached JSON
Limitations:
- Offline writes are tricky
- If you insert or update rows offline, they are not reflected in cached SELECT responses
- Updating all affected signatures requires rewriting cached JSON blobs
- Risk of divergence if multiple queries overlap
Open Question:
Does a wrapper approach scale, or should
supabase-ktconsider a first‑classOfflinePostgrestplugin with deeper integration?
This might allow:
- Built-in query signature tracking
- Automatic selection propagation
- Row-based caching instead of “response blob” caching
- More reliable merge and replay semantics
4. Storage Offline Thoughts
Downloads
We store files locally at:
<baseDir>/storage/<bucket>/<object_path>
val bucket = offline.storage("asset_images")
// Returns a File if local copy exists or is downloaded.
// Returns null if offline + no cached file.
val localFile = bucket.ensureLocalFile(
path = "12345/photo1.jpg",
isPublic = true
)
This mirrors how Firebase Storage works offline:
If the file has ever been downloaded, it is available offline.
This also avoids solutions like Base64‑storing blobs in SQLite.
Uploads
Supabase’s TUS-capable resumable uploads (via supabase-kt) already work well:
- Perfect for large images
- Also works for PDFs, documents, other binary files
- Cache is persisted by fingerprint → upload URL
- Survives app restarts or OS process kills
Open Questions:
-
Should this be a plugin?
Something like:install(OfflineStorage)instead of our wrapper around
BucketApi. -
Should supabase‑kt expose local file metadata hooks?
E.g. helpers for contentType detection, file hashing, etc. -
Should Storage support RLS-like rules offline?
Hard problem; probably out of scope.
5. Insert / Update / Delete While Offline (???)
Right now this is the biggest unsolved challenge.
Ideas:
A. Queue raw PostgREST requests (Firestore-style)
Store raw PostgREST REST payloads:
POST /rest/v1/assets
PATCH /rest/v1/assets?id=eq.123
DELETE /rest/v1/assets?id=eq.999
Then replay them when online.
Pros:
- Simple
- No schema needed
- Mirrors the network exactly
Cons:
- Cached SELECT results become stale
- Requires rewriting cached responses after each replay
B. Store row-level operations directly
Track mutations by primary key:
[ { table: "assets", type: "update", id: "...", payload: {...} } ]
Pros:
- Easier conflict resolution
- DB-friendly structure
Cons:
- Requires schema
- Does not naturally encode multi-row updates or filters
We don’t yet know which direction is “correct” long-term.
6. Why We Are Focusing on PostgREST + Storage First
We heavily rely on:
- Images
- PDFs
- Other binary documents
Coil only helps with image caching (and even there, PDF support is experimental).
Supabase Storage needs to reliably deliver large files offline so the UI can operate fully without internet.
Happy to collaborate, contribute code, or provide more detailed write‑ups if helpful!