Documentation Index
Fetch the complete documentation index at: https://setup.despia.com/llms.txt
Use this file to discover all available pages before exploring further.
The PowerSync integration is fully built and production-ready. It will become publicly available when the Despia V4 editor launches shortly. To enable it for your app in the meantime, contact Despia customer support at support@despia.com.
Installation
- Bundle
- CDN
Two-layer model
@despia/powersync exposes two layers:
- Local SQLite is available as soon as
db.init()succeeds and migrations apply. No token, no network, no cloud setup required. - Cloud sync lives under
db.powersync.*. It only starts afterdb.powersync.connect({ token })is called with a valid user-scoped JWT.
API Reference
active
Check whether the native PowerSync bridge is available in the current runtime.active() only checks bridge presence. It does not mean SQLite is initialized or sync is connected.
db.init
Initialize the database with a schema and target schema version. Call this once at startup, before any queries, migrations, or sync calls.Describes the tables the sync engine should map. Each key is a table name. Each value declares the columns and optional indexes for that table.Column types map directly to SQLite affinity types:
'text', 'integer', or 'real'. Indexes are optional and declared as a map of index name to an array of column names.Positive integer matching the latest migration version for this schema. Native uses this to know when to promote the pending schema to active.
Optional database name. Defaults are handled by native if omitted.
db.schema
Read the currently active schema state from native. Useful for figuring out which migrations are still pending.The active schema currently installed in native.
The active database name.
Hash of the active schema for change detection.
The schema version most recently passed to
db.init().The highest migration version that has been successfully applied.
Response Example
Response Example
db.migrate
Run schema migrations on startup. The runtime tracks the installed version and only executes statements for versions higher than the current one. When your current schema is at versionN and the device still needs migrations 1..N, pass all pending statements in one db.migrate(N, statements) call. Native commits or rolls back the full upgrade as one transaction.
BatchStatement objects with parameters.
Target migration version. Should match
SCHEMA_VERSION. Native uses this to decide when to promote the pending schema to active.Array of SQL statements to run for this version.
db.query
Fetch multiple rows from local SQLite. Instant, no network.- Basic
- With params
SQL SELECT statement.
Optional array of values bound to
? placeholders.db.get
Fetch a single row. Returnsnull if no match found.
db.execute
Run a single write statement.Number of rows affected.
Row ID of the last inserted row (INSERT only, when applicable).
db.batch
Run multiple write statements atomically.Array of results, one per statement.
db.transaction
Run a group of statements with full rollback on failure.db.watch
Subscribe to a query. Fires the callback immediately with the current result set, then again whenever matching data changes, including changes arriving from sync.- Without params
- With params
db.powersync.connect
Start cloud sync. Pass a short-lived JWT minted by your backend for the signed-in user.A short-lived JWT signed by your backend. Identifies the user to PowerSync.
db.powersync.sync
Trigger a manual sync.db.powersync.sync() as a trigger, then read status with db.powersync.status() or subscribe with db.powersync.events.status().
db.powersync.status
Read the current sync state.Whether the sync engine is connected to the PowerSync instance.
ISO timestamp of the last successful sync, or
null if never synced.Whether local writes are currently being uploaded.
Whether data is currently being downloaded from the backend.
Response Example
Response Example
db.powersync.events.status
Subscribe to sync state changes.db.watch() instead.
PowerSync auth and tokens
db.powersync.connect({ token }) gives the native PowerSync engine a token for the current signed-in user. It does not log the user into your app, and it 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.
- PowerSync sync rules decide which rows that verified user can sync.
Token flow
Your backend signs the JWT with the key or secret configured in PowerSync Client Auth. The native PowerSync SDK then connects to PowerSync with that token, and PowerSync verifies signature,kid, audience, expiry, and subject.
PowerSync dashboard setup
In the PowerSync dashboard, configure auth before expecting real sync to work:- Open your PowerSync project.
- Go to Client Auth and configure the same JWT verification method your backend uses.
- Configure sync rules or streams that use the authenticated user identity.
| Field | Purpose |
|---|---|
sub | The application user ID. PowerSync rules use this as the user identity. |
aud | Must match the PowerSync instance URL or configured audience. |
iat / exp | Token issue and expiry times. Keep expiry short. |
kid | Header key id. Must match the key configured in PowerSync Client Auth. |
| custom claims | Optional app data such as team, role, or project claims if your rules need them. |
Sync rules
PowerSync verifies who the user is from the token. Your sync rules decide what that user can sync. A simple rule is conceptually:sub = "user_123", rules should only sync rows authorized for user_123. For team, organization, or project data, include the required claims in the token or resolve membership in your backend or PowerSync rules. Do not issue broad tokens that allow every user to sync every row unless that is truly intended.
Before shipping, test with two users and confirm user A never receives user B’s private rows.
Client code
Backend token endpoint
This example uses HS256 because it is compact. Match the algorithm,kid, secret or key, audience, and claims to your own PowerSync Client Auth settings.
Supabase and Firebase
If your app already uses Supabase Auth or Firebase Auth, you may not need a custom token endpoint. PowerSync can be configured to verify those provider JWTs directly when Client Auth, audience, and JWKS settings match your provider. Native does not implement row-level authorization itself. Native passes the token into the real PowerSync SDK and reports real sync status and errors. Row-level authorization belongs in your PowerSync sync rules.Migrations
Schema describes the expected shape. Migration SQL changes the actual SQLite file. You usually need both. Keep schema and migrations together:- Update
CURRENT_SCHEMA. - Increase
SCHEMA_VERSION. - Add a migration with the new version.
- Run all pending migration statements with
db.migrate(SCHEMA_VERSION, pendingStatements). - 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:Errors and validation
db.init(), db.migrate(), and other methods throw a PowerSyncError when validation fails. Inspect code and details to handle errors.
Error codes
| Code | Source | Meaning | Typical fix |
|---|---|---|---|
schema_required | SDK or native | Missing or empty schema, or no active schema for a schema-dependent native operation. | Call db.init({ schema, schemaVersion }), apply migrations, then retry. |
invalid_schema | SDK or native | Schema shape is malformed. | Check error.details[] and fix the listed paths. |
invalid_options | SDK or native | Method options are malformed. | Pass the documented options object and valid field types. |
credentials_required | Native | Sync needs a token. | Call db.powersync.connect({ token }). |
sync_not_configured | Native | Native PowerSync app ID or URL config is missing. | Fix native PowerSync config. |
sync_not_initialized | Native | Native sync engine could not start or is not ready. | Ensure active schema, migrations, credentials, and native SDK setup are complete. |
migration_validation_failed | Native | Migration SQL failed or expected schema shape was not reached. | Fix SQL or schema before retrying db.migrate(). |
database_not_initialized | Native | Native SQLite database is not open. | Check native bridge and database setup. |
request_timeout | SDK | Native did not respond to a bridge request within the timeout. | Ensure native completes requests promptly. |
Validation reasons
Thereceived column shows examples of bad input that trigger each error.
| Reason | Path example | Expected | Example received |
|---|---|---|---|
missing_or_invalid_schema | schema | non-empty object | undefined, null, array |
empty_schema | schema | object with at least one table | empty object |
empty_table_name | schema | non-empty table name | empty string |
invalid_table_definition | schema.users | object with columns map | string, array, null |
invalid_columns | schema.users.columns | non-empty object | string, array, null |
empty_columns | schema.users.columns | object with at least one column | empty object |
empty_column_name | schema.users.columns | non-empty column name | empty string |
invalid_column_type | schema.users.columns.age | ["text", "integer", "real"] | varchar, number, boolean |
invalid_indexes | schema.users.indexes | object mapping index names to column arrays | string, array, null |
empty_index_name | schema.users.indexes | non-empty index name | empty string |
invalid_index_columns | schema.users.indexes.by_email | non-empty string array | empty array, string, null |
invalid_index_column_name | schema.users.indexes.by_email | non-empty string | empty string, number |
unknown_index_column | schema.users.indexes.by_row | existing column name | row |
invalid_schema_version | options.schemaVersion | positive integer | 0, 1.5, string |
invalid_database_name | options.databaseName | non-empty string | empty string, number |
invalid_migration_version | version | positive integer | 0, 1.5, string |
invalid_migration_statements | statements | non-empty string array or BatchStatement[] | empty array, null |
invalid_migration_sql | statements.0 | non-empty SQL string | empty string, number |
empty_migration_sql | statements.0.sql | non-empty SQL string | empty string |
invalid_token | config.token | non-empty string | empty string, undefined |
invalid_url | config.url | non-empty string | empty string, number |
Fallback flow
If a schema upgrade fails, do not start sync with the new schema. Fall back to the active schema state if you can run against it.db.schema().
Sync flow
React Hook
TypeScript types
Environment check
@despia/powersync requires the native bridge and will throw in a standard browser. Gate calls behind this check if your app also runs on web.
Resources
NPM Package
@despia/powersync
GitHub
despia-native/despia-powersync
PowerSync
Backend setup, schema config, and sync rules