(updated)
|
min. read

Offline-First Apps Made Simple: Supabase + PowerSync

Kobie Botha

In the age of AI, offline-first still matters

The year is 2025. We are all more connected than ever, constantly chatting with LLMs. Yet this recently happened: 

A tweet by Notion founder, Ivan Zhao, about offline functionality

This was Notion’s top requested feature for 5 years, and it took a lot of effort to ship it. Use cases that need offline support are plentiful: navigation, productivity, chat, workout tracking and more. Supabase is a fantastic fit for all of these use cases, but how do we make our apps work really well when our users are offline?

In this post, I’ll be making my case that Supabase + PowerSync is one of the best stacks on the market for building offline-first web and mobile apps. First, some background.

The rise of sync engines

Sync engines have gained popularity in recent years. They generally come in two flavors. On the one hand, you have modern Firebase alternatives such as Convex and InstantDB. On the other, you have pluggable sync engines that integrate with an existing database. We are, of course, more interested in the second flavor because… well… maybe we just like Postgres 😀

There are three pluggable sync engines available today: ElectricSQL, Zero and PowerSync. This post is not a direct comparison of them; all integrate well with Supabase. The focus in this post is on building offline-first apps, and of the three, PowerSync is the only one with first-class offline support.

At the 2025 Local-First Conference in Berlin, Aaron Boodman from Zero (a sync engine with some nice features) was asked about offline support. He noted that offline presents significant UX challenges, and stated that offline is out of scope for Zero for the time being. Similarly, offline is out of scope for ElectricSQL by definition since it does not concern itself with client-side persistence; developers must implement their own persistence.

When is offline-first really hard?

When syncing a single user’s data, you typically don’t need a sync engine. Most of the time it’s quite straightforward, and there are plenty of writeups that can guide you through implementation. 

The complexity arises when building collaborative apps, where multiple users need to see the same state. This quickly becomes a hard problem:

  • Partial sync: The system should only sync a subset of data to each user, not the entire backend database. Additionally, these subsets are often defined dynamically based on the data, such as team membership or shared folders.
  • Consistency: If user 1 performs an action after user 2, then all clients must observe the same sequence of events.
  • Conflicts: When a client has been offline for a long time and reconnects, its local changes must be reconciled with any changes made to the same data by other clients during that time.
  • Reliability: Any solution must scale well, and handle production issues, such as storage corruption

As of writing, LLMs can’t solve these problems for you.

Enter PowerSync

PowerSync is a sync engine that synchronizes an in-app SQLite database with your backend database like Supabase. It provides solutions to the challenges outlined above faced when building offline-first apps at scale.

PowerSync’s bucket system is what solves partial dynamic sync at scale, a particularly thorny problem. Think of buckets as subsets of your Postgres data that can be synced as a whole to one or more users. PowerSync also guarantees causal consistency across all synced buckets, avoiding weird scenarios such as your takeout order arriving before you ordered it 😆 

PowerSync scales horizontally: 

  • The overall system can keep millions of rows in a client SQLite database synced
  • The bucket system scales to thousands of buckets per user (millions of buckets overall)
  • User scaling:
    • Millions of users/clients in total
    • Hundreds of thousands of concurrently connected users, with scaling above that possible with extra configuration

Combined with Supabase, deployment becomes really straightforward. Supabase uniquely provides a set of technologies that solve common headaches:

  • Cross-platform client libraries: Both PowerSync and Supabase have libraries for Flutter/Dart, JS/Web, React Native, Swift, Kotlin and more.
  • Auth: Simple config to enable Supabase Auth with either PowerSync Cloud or self-hosted PowerSync Open Edition. PowerSync already supports Supabase asymmetric JWTs.
  • PostgREST: Used by PowerSync for uploading client writes. Supabase Edge Functions are a great option for more advanced persistence logic.
  • RLS: For controlling write permissions. Especially powerful when combined with PostgREST.
  • Replication tools: PowerSync uses logical replication, which Supabase supports well. Custom roles can be granted replication privileges.
  • Scales to millions 😉

Conflicts

As always, conflicts deserve their own section. Conflicts happen when multiple clients modify the same piece of data — often while offline — and those changes require reconciliation upon reconnection. This is a core challenge in collaborative apps. Mishandling the reconciliation can lead to data loss or inconsistency, and that in turn leads to grumpy users.

In my experience of building dozens of enterprise grade offline-first apps over a decade, I can confidently say that a last-write-wins (LWW) resolution strategy is sufficient for ~95% of apps where users are working with shared state. In LWW, the most recent write — as timestamped by the server — is persisted. A common practice when choosing LWW is to implement audit logging on your backend to track which user changed which columns in a row, at what time, and what the new values are. PGAudit could be useful here, depending on your requirements. 

PowerSync gives developers the tools to decide how they want to handle conflicts, instead of avoiding offline entirely. Developers get LWW conflict resolution by default when using the provided %%SupabaseConnector%%, with the option to customize the behavior.  You can implement your own custom merge algorithm/logic — see Matthew Weidner’s shining example of this, or you can use CRDTs. See our Yjs demo and CRDT docs for more details on that.

Conclusion: Supabase + PowerSync = the ultimate stack for offline-first web and mobile apps 

Offline support is as relevant as ever. Among the family of pluggable sync engines, PowerSync includes offline capabilities, partial sync, consistency, customizable conflict resolution, and scaling to large user bases.

The combination of Supabase + PowerSync provides cross-platform client libraries, easy authentication setup, PostgREST for handling writes, RLS for access control, logical replication support and more. Using last-write-wins (LWW) as a conflict strategy works for most shared-state scenarios, with many options for custom resolution. 

The Supabase + PowerSync combo is a great choice for building sophisticated multi-user offline-first web and mobile apps.

Start building

To get started with PowerSync Cloud, see our Supabase integration guide. Alternatively for self-hosters or if you prefer local development, see our Supabase + PowerSync starter template.