The PowerSync integration is fully built and production-ready. The cloud sync component will become publicly available when the Despia V4 editor launches. To enable it already contact our support via the Despia live chat and share your PowerSync URL + Bundle ID.
Installation
- Bundle
- CDN
Check for the native runtime
Returnstrue when the native PowerSync runtime is present, false in a standard browser. Use this to guard all database calls when your web app also runs outside Despia.
active() only confirms runtime presence. It does not mean SQLite is initialized or sync is connected.
Initialize the database
Call once at startup, before any queries, migrations, or sync calls. Registers the schema and target version with native as pending state.db.init() validates the schema object before calling native. If validation fails it throws a PowerSyncError with code: "invalid_schema" and a details array listing every path that failed.
Read the active schema state
Returns the schema currently active in native. Use this to determine which migrations are still pending.Response example
Response example
Run migrations
Apply pending SQL statements to the SQLite file. Native tracks the installed version and only executes statements for versions higher than the current one. Pass all pending statements for a version in a single call so native can commit or roll back the full upgrade as one transaction.
When your schema is at version
N and the device needs migrations 1 through N, pass all pending statements in one db.migrate(N, statements) call rather than calling migrate() once per version.
Query multiple rows
Fetches all matching rows from local SQLite. Instant, no network.Query a single row
Fetches the first matching row from local SQLite. Returnsnull if no row matches.
Write a single row
Runs one INSERT, UPDATE, or DELETE statement.Write multiple rows atomically
Runs an array of write statements as one batch. All statements succeed or none do.{ results: ExecuteResult[] }, one result per statement.
Run a transaction
Runs a group of statements with full rollback on any failure.tx object exposes the same execute API as db.execute.
Subscribe to a live query
Fires the callback immediately with the current result set, then again whenever matching data changes, including rows updated by sync.Connect to cloud sync
Starts sync for the signed-in user. Pass a short-lived JWT minted by your backend. Native reads the static PowerSync app ID and instance URL from native config.
Do not call this before
db.init() and migrations. Sync will fail silently or throw if no active schema exists.
Trigger a manual sync
Schedules an immediate sync cycle. Sync completes asynchronously.db.powersync.sync() as a trigger, then read the result with db.powersync.status() or subscribe with db.powersync.events.status().
Read current sync state
Returns a snapshot of the sync engine state.Response example
Response example
Subscribe to sync state changes
Fires the callback whenever sync state changes. Use this for sync indicators, offline banners, and last-synced timestamps. For row data, usedb.watch() instead.
Upload local writes to your backend
Register a handler that native calls when it has pending CRUD writes to send to your backend. Use this when your upload runs in JavaScript.upload_complete and the native queue is finalized. If the handler throws, the SDK reports the error back to native and PowerSync retries later. Calling events.upload() again replaces the previous handler, so register one handler per session.
Create a search index
Creates or updates a native full-text index on a table. Resolves when the index is fully built, including asynchronous builds on large tables. Native validates that the source table and columns exist.
Native uses SQLite FTS5 for full-text and prefix search, and native trigram/edit-distance ranking for
mode: "fuzzy" when supported by the app build.
Check search index build state
Returns the current native build state for a search index. Useful for showing progress while a large index builds.db.search.indexStatus('postsSearch') for compatibility.
Response example
Response example
Subscribe to search index build events
Subscribe to the native async build lifecycle. Useful for showing progress in the UI whiledb.search.index() or db.search.rebuildIndex() waits.
db.search.events.index.progress, db.search.events.index.built, and db.search.events.index.failed are aliases for compatibility.
List search indexes
Returns all native search indexes registered for the database.Query a search index
Queries a native search index with plain, prefix, or fuzzy matching.Rebuild a search index
Rebuilds the index from the current table data. Resolves when the rebuild is complete. Use this after large migrations or data repairs.Drop a search index
Removes a search index permanently.PowerSync auth and tokens
db.powersync.connect({ token }) gives the native sync engine a token for the current signed-in user. It does not log the user into your app and does not create the token. Three separate pieces are involved: your app auth decides who the user is, PowerSync Client Auth verifies the token native sends to PowerSync, and PowerSync sync rules decide which rows that verified user can sync.
The token identifies the user. If a row syncs into local SQLite, your app can query it. Private rows must be blocked by sync rules before they reach the device.
Token flow
Your backend signs the JWT with the key or secret configured in PowerSync Client Auth. PowerSync verifies the signature,kid, audience, expiry, and subject.
PowerSync dashboard setup
1
Open your PowerSync project
Go to powersync.com and open your project or instance.
2
Configure Client Auth
Go to Client Auth and configure the same JWT verification method your backend uses.
3
Configure sync rules
Set up sync rules or streams that use the authenticated user identity to control which rows each user can sync.
For production, asymmetric JWT signing with JWKS is preferred so PowerSync can verify tokens with a public key while your backend keeps the private signing key. HS256 works for development if it exactly matches your PowerSync Client Auth configuration.
Mint a token on your backend
Fetch the token on the client
Supabase and Firebase
If your app already uses Supabase Auth or Firebase Auth, you may not need a custom token endpoint. PowerSync can verify those provider JWTs directly when Client Auth, audience, and JWKS settings match your provider.Migrations reference
Schema describes the expected shape. Migration SQL changes the actual SQLite file. You always need both. Keep schema and migrations together in one module:CURRENT_SCHEMA, increase SCHEMA_VERSION, add a migration with the new version, run all pending statements with db.migrate(SCHEMA_VERSION, pendingStatements), and only then run queries or sync that depend on the new shape.
Add a column
Add a table
Rename or reshape a table
Use copy-and-swap. SQLite does not supportALTER TABLE ... RENAME COLUMN on older versions.
Errors
db.init(), db.migrate(), and other methods throw a PowerSyncError when validation fails.
Error codes
Validation reasons
Fallback on failed migration
If a migration fails, do not start sync with the new schema. Fall back to the previously active schema if your app can run against it.Standard PowerSync flow
This is the correct call order on every app start. Theactive() guard is required when your web app also runs outside Despia.
TypeScript types
Exports
Resources
NPM Package
@despia/powersync
GitHub
despia-native/despia-powersync
PowerSync
Backend setup, schema config, and sync rules
Support
Check for the native runtime
Returnstrue when the native PowerSync runtime is present, false in a standard browser. Use this to guard all database calls when your web app also runs outside Despia.
active() only confirms runtime presence. It does not mean SQLite is initialized or sync is connected.
Initialize the database
Call once at startup, before any queries, migrations, or sync calls. Registers the schema and target version with native as pending state.db.init() validates the schema object before calling native. If validation fails it throws a PowerSyncError with code: "invalid_schema" and a details array listing every path that failed.
Read the active schema state
Returns the schema currently active in native. Use this to determine which migrations are still pending.Response example
Response example
Run migrations
Apply pending SQL statements to the SQLite file. Native tracks the installed version and only executes statements for versions higher than the current one. Pass all pending statements for a version in a single call so native can commit or roll back the full upgrade as one transaction.
When your schema is at version
N and the device needs migrations 1 through N, pass all pending statements in one db.migrate(N, statements) call rather than calling migrate() once per version.
Query multiple rows
Fetches all matching rows from local SQLite. Instant, no network.Query a single row
Fetches the first matching row from local SQLite. Returnsnull if no row matches.
Write a single row
Runs one INSERT, UPDATE, or DELETE statement.Write multiple rows atomically
Runs an array of write statements as one batch. All statements succeed or none do.{ results: ExecuteResult[] }, one result per statement.
Run a transaction
Runs a group of statements with full rollback on any failure.tx object exposes the same execute API as db.execute.
Subscribe to a live query
Fires the callback immediately with the current result set, then again whenever matching data changes, including rows updated by sync.Connect to cloud sync
Starts sync for the signed-in user. Pass a short-lived JWT minted by your backend. Native reads the static PowerSync app ID and instance URL from native config.
Do not call this before
db.init() and migrations. Sync will fail silently or throw if no active schema exists.
Trigger a manual sync
Schedules an immediate sync cycle. Sync completes asynchronously.db.powersync.sync() as a trigger, then read the result with db.powersync.status() or subscribe with db.powersync.events.status().
Read current sync state
Returns a snapshot of the sync engine state.Response example
Response example
Subscribe to sync state changes
Fires the callback whenever sync state changes. Use this for sync indicators, offline banners, and last-synced timestamps. For row data, usedb.watch() instead.
Upload local writes to your backend
Register a handler that native calls when it has pending CRUD writes to send to your backend. Use this when your upload runs in JavaScript.upload_complete and the native queue is finalized. If the handler throws, the SDK reports the error back to native and PowerSync retries later. Calling events.upload() again replaces the previous handler, so register one handler per session.
Create a search index
Creates or updates a native full-text index on a table. Resolves when the index is fully built, including asynchronous builds on large tables. Native validates that the source table and columns exist.
Native uses SQLite FTS5 for full-text and prefix search, and native trigram/edit-distance ranking for
mode: "fuzzy" when supported by the app build.
Check search index build state
Returns the current native build state for a search index. Useful for showing progress while a large index builds.db.search.indexStatus('postsSearch') for compatibility.
Response example
Response example
Subscribe to search index build events
Subscribe to the native async build lifecycle. Useful for showing progress in the UI whiledb.search.index() or db.search.rebuildIndex() waits.
db.search.events.index.progress, db.search.events.index.built, and db.search.events.index.failed are aliases for compatibility.
List search indexes
Returns all native search indexes registered for the database.Query a search index
Queries a native search index with plain, prefix, or fuzzy matching.Rebuild a search index
Rebuilds the index from the current table data. Resolves when the rebuild is complete. Use this after large migrations or data repairs.Drop a search index
Removes a search index permanently.PowerSync auth and tokens
db.powersync.connect({ token }) gives the native sync engine a token for the current signed-in user. It does not log the user into your app and does not create the token. Three separate pieces are involved: your app auth decides who the user is, PowerSync Client Auth verifies the token native sends to PowerSync, and PowerSync sync rules decide which rows that verified user can sync.
The token identifies the user. If a row syncs into local SQLite, your app can query it. Private rows must be blocked by sync rules before they reach the device.
Token flow
Your backend signs the JWT with the key or secret configured in PowerSync Client Auth. PowerSync verifies the signature,kid, audience, expiry, and subject.
PowerSync dashboard setup
1
Open your PowerSync project
Go to powersync.com and open your project or instance.
2
Configure Client Auth
Go to Client Auth and configure the same JWT verification method your backend uses.
3
Configure sync rules
Set up sync rules or streams that use the authenticated user identity to control which rows each user can sync.
For production, asymmetric JWT signing with JWKS is preferred so PowerSync can verify tokens with a public key while your backend keeps the private signing key. HS256 works for development if it exactly matches your PowerSync Client Auth configuration.
Mint a token on your backend
Fetch the token on the client
Supabase and Firebase
If your app already uses Supabase Auth or Firebase Auth, you may not need a custom token endpoint. PowerSync can verify those provider JWTs directly when Client Auth, audience, and JWKS settings match your provider.Migrations reference
Schema describes the expected shape. Migration SQL changes the actual SQLite file. You always need both. Keep schema and migrations together in one module:CURRENT_SCHEMA, increase SCHEMA_VERSION, add a migration with the new version, run all pending statements with db.migrate(SCHEMA_VERSION, pendingStatements), and only then run queries or sync that depend on the new shape.
Add a column
Add a table
Rename or reshape a table
Use copy-and-swap. SQLite does not supportALTER TABLE ... RENAME COLUMN on older versions.
Errors
db.init(), db.migrate(), and other methods throw a PowerSyncError when validation fails.
Error codes
Validation reasons
Fallback on failed migration
If a migration fails, do not start sync with the new schema. Fall back to the previously active schema if your app can run against it.Standard PowerSync flow
This is the correct call order on every app start. Theactive() guard is required when your web app also runs outside Despia.