(updated)
|
min. read

Introducing the PowerSync Capacitor SDK

Kobie Botha

Introducing the PowerSync Capacitor SDK

We're excited to announce the release of the PowerSync Capacitor SDK, bringing native SQLite performance to Capacitor applications on iOS and Android while maintaining seamless compatibility with web platforms.

The PowerSync Capacitor SDK extends our Web SDK to automatically use native SQLite implementations when your app runs on mobile platforms. This means you can write your code once and get:

  • Native SQLite on iOS and Android via the Capacitor Community SQLite plugin
  • WA-SQLite on web platforms using IndexedDB or OPFS storage
  • Automatic platform detection of the above (handled by the SDK)
  • All the benefits of synced SQLite: bulletproof persistence, instant reactivity, and automatically synced state

Why We Built This

As more developers adopted PowerSync for Capacitor apps, we heard consistent feedback about the need for better mobile performance and persistence:

Roadmap User 1 quote:

I would like to add sync to my Android and iOS apps built with Capacitor. I need full local-first offline support. As I understand it, native SQLite storage is the only real reliable permanent storage option on Capacitor mobile apps, since other options such as IndexedDB may be cleared by the OS at any point

Roadmap User 2 quote:

local-first for web & mobile apps without switching the codebase! would allow us to not have to use react native and rewrite all our frontend

Roadmap User 3 quote:

 webiew storage seems unreliable. If powersync doesn’t support native sqlite for persistence, I might have to use rxdb instead of powersync. Thank you for working on this!

These insights drove us: Developers want the simplicity of web code with the reliability of native mobile databases. Our Capacitor SDK delivers that.

The Inside Story: How We Built It

The challenge was interesting: Capacitor runs web applications in native web views, but those environments don’t provide access to native SQLite. We needed to bridge between PowerSync’s JavaScript layer and platform-specific SQLite implementations.

Platform detection and driver swapping

The SDK uses Capacitor's platform detection APIs to determine the runtime environment. When running on iOS or Android, it automatically swaps WA-SQLite for the Capacitor Community SQLite driver, which provides JavaScript bindings to native SQLite implementations on each platform.

import { PowerSyncDatabase } from '@powersync/capacitor';
import { Schema } from '@powersync/web';

const db = new PowerSyncDatabase({
  schema: new Schema({...}),
  database: {
    dbFilename: "mydatabase.sqlite"
  }
});

// Automatically uses:
// - Native SQLite on iOS/Android 
// - WA-SQLite on web platforms

Solving SQLite Extension Loading

PowerSync requires two critical capabilities from any SQLite implementation:

  1. SQLite extension loading: our PowerSync Core extension handles the sync protocol's complexity
  2. Table update notifications: for reactive queries

The Capacitor Community SQLite plugin presented some challenges here. While they added APIs for enabling and loading SQLite extensions, these APIs weren't fully implemented on native platforms ‒ they would throw errors on Android and iOS.

Rather than fork and maintain an entire SQLite library, we initially took a more surgical approach. The Capacitor Community SQLite plugin uses SQLCipher as its underlying SQLite library on mobile platforms, exposing it through Java (Android) and Swift (iOS) bindings. We created our own minimal Capacitor plugin that exposes a %%registerCore%% native method, allowing us to interface directly with SQLCipher to load our Core extension automatically for any opened connection.

This approach got even cleaner recently. SQLCipher Android added support for enabling dynamic extension loading by default for all connections. Once the Capacitor Community SQLite library updated their Android SQLCipher dependency, we no longer needed direct SQLCipher integration on Android. We still use this approach for iOS, but the architecture is cleaner and more maintainable.

Reactive Queries and Update Hooks

The second requirement ‒ table update notifications – is essential for PowerSync's reactivity model. When data changes (whether from local mutations or changes from background sync), watched queries need to re-execute and update your UI.

The Capacitor Community SQLite library doesn't provide update hooks, however as part of a different project, we recently implemented our own version of update hooks directly in the PowerSync Core extension. This gives us access to table change notifications at the SQLite level, enabling reactive queries to work seamlessly.

This architecture means that features like %%useQuery()%% in React work identically across platforms. Your components automatically re-render when data changes, regardless of whether the app is running on web, iOS, or Android.

Performance and Reliability Benefits

By using native SQLite on mobile platforms, Capacitor users get:

  • Improved Database Persistence: Native SQLite provides more reliable data storage than browser-based solutions, with proper filesystem integration and crash recovery
  • Enhanced Query Performance: Direct access to native SQLite implementations delivers better performance, especially for complex queries and large datasets
  • Lower Latency: Native execution eliminates the JavaScript-to-WASM boundary that browser-based SQLite implementations require. We ran some initial benchmarks and saw a significant speedup versus IndexedDB.

Resources for Builders

See our official Capacitor SDK documentation for installation instructions and API reference.

Have an enjoyable cup of coffee with our example app: it showcases the SDK in action on Web, iOS and Android. 

If you get stuck or want to share what you’re building, join our Discord server to connect with other PowerSync developers and our engineering team.

Known Limitations and Roadmap

This release is just the beginning. First and foremost we’re looking for your feedback! This will have a big impact on our roadmap. Additionally, if we see uptake from the community, we’ll be working on the known limitations. Lastly, we're also exploring opportunities to contribute upstream to the Capacitor Community SQLite plugin, potentially upstreaming some of our extension loading improvements to benefit the broader community.