Skip to content

Use powersync_sqlite_nostd for internal queries#14

Merged
simolus3 merged 3 commits intomainfrom
sqlite-nostd
Apr 8, 2026
Merged

Use powersync_sqlite_nostd for internal queries#14
simolus3 merged 3 commits intomainfrom
sqlite-nostd

Conversation

@simolus3
Copy link
Copy Markdown
Collaborator

@simolus3 simolus3 commented Apr 8, 2026

We heavily rely on the rusqlite crate in our public APIs (e.g. as a Deref target for leased connections, or to auto-watch rusqlite::Statements). It's a nice crate providing safe and ergonomic bindings to SQLite, and it makes sense to center parts of our Rust APIs around that.

However, we're also exploring using the Rust SDK in scenarios where rusqlite might be less helpful:

  1. As a framework used to implement the Swift SDK: Here, we want to be able to swap out the SQLite library to switch between sqlite3 and SQLite3MultipleCiphers. For that, we need Rust code to reference SQLite APIs as undefined symbols that would get resolved with the app's linker later. Rusqlite depends on libsqlite3-sys, which either adds a link dependency on -lsqlite3 or bundles SQLite with the app. Neither option is great for Swift.
  2. This is less relevant, but rusqlite doesn't support nostd targets. We don't currently support them either, but rusqlite is one of the bigger blockers towards that and running PowerSync on embedded targets would be kind of neat.

So, this makes rusqlite an optional but default dependency. Internally, this adds the SqliteConnection struct which wraps a rusqlite::Connection if that feature is enabled or a ManagedConnection otherwise. Either way, internal statements are run by obtaining a *mut sqlite3 pointer and then using powersync_sqlite_nostd APIs.

Comment thread powersync/src/db/pool.rs
@simolus3 simolus3 marked this pull request as ready for review April 8, 2026 15:48
@simolus3 simolus3 requested a review from rkistner April 8, 2026 15:48
Copy link
Copy Markdown

@rkistner rkistner left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I didn't follow the specific implementation, but it makes sense to have rusqlite be an optional dependency.

One question: Would it make sense to have a separate crate for rusqlite support, instead of having it be an optional feature? That's how we're structuring things in some other places (e.g. drizzle/kysely support in the JS SDKs), but I'm not familiar enough with how these kinds of optional dependencies are typically structured in Rust crates.

@simolus3
Copy link
Copy Markdown
Collaborator Author

simolus3 commented Apr 8, 2026

but I'm not familiar enough with how these kinds of optional dependencies are typically structured in Rust crates

At least from what I've seen, it looks like these integrations are commonly part of the main crate with optional features to disable them (for example, virtually every crate defining data structures has an optional serde feature + dependency to provide serialization). I think that makes sense since JS/Dart/Kotlin don't really have the concept of package features and dependencies bound to those features. in Rust, if we have an optional feature with dependencies a user doesn't want, they can just disable that and pay none of the cost (unlike in JS where it's difficult to express that some APIs need a specific optional dependency, or where those dependencies are more likely to contribute to dependency bloat).

Another thing we have in Rust is crate-level visibility, so different integrations could share internals that aren't part of a public API for which we'd have to maintain backwards compatibility. A downside is that if we need to make a breaking change affecting only one integration, we'd still have to make it a major upgrade on the crate which is annoying for everyone.

FWIW we already have some optional features (the tokio and smol-rs integrations are both optional features instead of additional crates). That model feels natural in Rust, but I can also see how larger integrations like ORMs make more sense as standalone crates. I've contemplated adding the tauri integration as an optional feature instead of a separate crate. But in the end, a separate crate was a better call since we want to maintain that with the JS SDK.

@simolus3 simolus3 merged commit 2fc180e into main Apr 8, 2026
2 checks passed
@simolus3 simolus3 deleted the sqlite-nostd branch April 8, 2026 19:08
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants