Local-first sync
that just works
Define queries and mutations once. Run them instantly on a local SQLite replica or on the server.
Try it — toggle a checkbox
- Learn about Valet
- Define a schema
- Write queries
- Learn about Valet
- Define a schema
- Write queries
Offline-first
Works offline
Toggle sync off and make changes — they queue up locally. Toggle sync back on and everything catches up. Mutations replay deterministically. No data loss.
- Buy groceries
- Walk the dog
- Ship feature
- Buy groceries
- Walk the dog
- Ship feature
Selective sync
Only sync what you need
The server database has all the rows. Sync filters control which ones reach each client. Try reassigning a task.
- Review PR #42
- Update docs
- Review PR #42
- Fix login bug
- Update docs
- Deploy staging
- Fix login bug
- Deploy staging
Conflict resolution
Replay, not merge
Most sync engines merge values with last-write-wins. Valet replays each mutation against current server state so both changes are preserved.
Click the buttons on both clients, then hit Reconnect.
10
10
Dual execution
One API, two databases
Same function signature. Switch between client SQLite and your server DB with one line.
// Local — instant, offline
export const list = defineQuery({
execution: 'local',
handler: async (ctx) =>
ctx.db.query('todos').collect(),
})
// Server — full dataset access
export const search = defineQuery({
execution: 'server',
handler: async (ctx, args) =>
ctx.db.query('todos')
.filter(q => q.eq('title', args.term))
.collect(),
})Deterministic replay
Write normal JavaScript
crypto.randomUUID(), Math.random(), and Date.now() are captured and replayed identically.
export const create = defineMutation({
handler: async (ctx, args) => {
const id = crypto.randomUUID()
const now = Date.now()
return ctx.db.insert('todos', {
title: args.title,
externalId: id,
createdAt: now,
})
},
})Why Valet
Local + server queries
Run queries instantly on a local SQLite replica, or on the server for full-dataset operations.
Offline-first with rebase
Mutations queue locally and replay against server state on reconnect. No last-write-wins data loss.
Deterministic replay
crypto.randomUUID(), Math.random(), and Date.now() are captured and replayed identically.
No vendor lock-in
Standard SQLite on both client and server. Your data is always portable.