PowerSync reads data from the Postgres Write-Ahead Log, MongoDB change streams, or MySQL binlog (coming soon).
Define sync rules to control which buckets of data should sync to which users, using SQL statements.
Data replicated from the backend database dynamically hydrates the data buckets on the PowerSync service, which are then streamed to relevant users’ local SQLite databases in real-time.
bucket_definitions:
# define your various buckets (specify any unique identifier for each)
user_lists_and_todos:
# parameter query: get parameters from the JWT token (e.g. user ID) and/or retrieve
# additional parameters from elsewhere in your database to use in your data queries
parameters: SELECT token_parameters.user_id as user_id
# data queries: using the aforementioned parameters, query the data to be synced.
# in this to-do list example, we are querying lists and todos that belong to the user
data:
- SELECT * FROM lists WHERE owner_id = bucket.user_id
- SELECT * FROM todos WHERE created_by = bucket.user_id
Read and write to a single SQLite database embedded in the client SDK.
// Local queries
await db.execute('SELECT * FROM lists WHERE id = ?', [id]);
// Local writes
await db.execute('INSERT INTO tasks(id, name) VALUES(uuid(), ?)', [name]);
await db.execute('UPDATE tasks SET completed = NOT completed WHERE id = ?', [task.id]);
// Live query — enables reactivity whenever results update
const results = usePowerSyncWatchedQuery('SELECT name, completed FROM tasks WHERE list_id = ?', [list_id]);
// Local queries
await db.execute('SELECT * FROM lists WHERE id = ?', [id]);
// Local writes
await db.execute('INSERT INTO tasks(id, name) VALUES(uuid(), ?)', [name]);
await db.execute('UPDATE tasks SET completed = NOT completed WHERE id = ?', [task.id]);
// Live query — enables reactivity whenever results update
db.watch('SELECT name, completed FROM tasks WHERE list_id = ?', [list_id]).map((results) { });
// Insert using Kysely query builder
await db.insertInto('users').values({ id: '1', name: 'John' }).execute();
// Query using Kysely query builder
const result = await db.selectFrom('users').selectAll().execute();
// Insert using Drift ORM
await appdb
.into(appdb.todoItems)
.insert(TodoItemsCompanion.insert(description: 'Test'));
// Watch a query on the Drift database
appdb.select(appdb.todoItems).watch().listen((todos) {
print('Todos: $todos');
});
// Local queries
await db.execute('SELECT * FROM lists WHERE id = ?', [id]);
// Local writes
await db.execute('INSERT INTO tasks(id, name) VALUES(uuid(), ?)', [name]);
await db.execute('UPDATE tasks SET completed = NOT completed WHERE id = ?', [task.id]);
// Live query — enables reactivity whenever results update
const results = usePowerSyncWatchedQuery('SELECT name, completed FROM tasks WHERE list_id = ?', [list_id]);
// Local queries
await db.execute('SELECT * FROM lists WHERE id = ?', [id]);
// Local writes
await db.execute('INSERT INTO tasks(id, name) VALUES(uuid(), ?)', [name]);
await db.execute('UPDATE tasks SET completed = NOT completed WHERE id = ?', [task.id]);
// Live query — enables reactivity whenever results update
db.watch('SELECT name, completed FROM tasks WHERE list_id = ?', [list_id]).map((results) { });
// Insert using Kysely query builder
await db.insertInto('users').values({ id: '1', name: 'John' }).execute();
// Query using Kysely query builder
const result = await db.selectFrom('users').selectAll().execute();
// Insert using Drift ORM
await appdb
.into(appdb.todoItems)
.insert(TodoItemsCompanion.insert(description: 'Test'));
// Watch a query on the Drift database
appdb.select(appdb.todoItems).watch().listen((todos) {
print('Todos: $todos');
});
Writes go through your backend, allowing you to apply any business logic, validations, authorization and conflict resolution strategy (including using CRDT data structures for fine-grained collaboration).
PowerSync treats the server as authoritative and automatically ensures all clients converge to the server state with causal consistency.
Local-first apps work with a local database and sync data in the background.
Real-time data streaming
Instantly reactive UI
Always available, works offline
Multi-user collaboration
Control data privacy
Start local-only or local-first
Ask questions and join in on discussions about local-first development.
Join DiscordFuture support for other databases, including Oracle, MySQL and MS SQL Server, is planned.
Please submit your ideas for frameworks and features that we should consider.