supabase-kt icon indicating copy to clipboard operation
supabase-kt copied to clipboard

[Feature request]: Add support for offline data persistence

Open jan-tennert opened this issue 1 year ago • 4 comments
trafficstars

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

jan-tennert avatar Oct 17 '24 11:10 jan-tennert

@grdsdev @dshukertjr, would love to hear your thoughts on this!

jan-tennert avatar Oct 17 '24 11:10 jan-tennert

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.

dshukertjr avatar Oct 18 '24 04:10 dshukertjr

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.

jan-tennert avatar Oct 18 '24 07:10 jan-tennert

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.

rohitjakhar avatar Sep 10 '25 14:09 rohitjakhar

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-kt consider a first‑class OfflinePostgrest plugin 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:

  1. Should this be a plugin?
    Something like:

    install(OfflineStorage)
    

    instead of our wrapper around BucketApi.

  2. Should supabase‑kt expose local file metadata hooks?
    E.g. helpers for contentType detection, file hashing, etc.

  3. 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!

nesfeder avatar Nov 13 '25 17:11 nesfeder