Sync that works offline.
A local-first sync engine for TypeScript, React, and Next.js. Every read is instant. Every write works offline. Every client converges.
Instant reads
All reads come from a local IndexedDB replica. No spinners, no round-trips.
Offline support
Mutations queue in a persistent outbox. Changes sync when you reconnect.
Fine-grained reactivity
MobX makes each field observable. Only affected components re-render.
Real-time collaboration
Yjs CRDT integration for multi-user editing of rich text and structured data.
Undo and redo
Transaction-based history tracking, built into the sync client.
Modular
Swap storage, transport, or reactivity adapters. Use only what you need.
Define your models
import { ClientModel, Model, Property } from "@stratasync/core"
@ClientModel("Todo", { loadStrategy: "instant" })
class Todo extends Model {
@Property() declare title: string
@Property() declare completed: boolean
}Create the client
import { createSyncClient } from "@stratasync/client"
import { createMobXReactivity } from "@stratasync/mobx"
import { createIndexedDbStorage } from "@stratasync/storage-idb"
import { GraphQLTransportAdapter } from "@stratasync/transport-graphql"
const client = createSyncClient({
storage: createIndexedDbStorage(),
transport: new GraphQLTransportAdapter({
endpoint: "/api/sync",
wsEndpoint: "wss://api.example.com/sync/ws",
}),
reactivity: createMobXReactivity(),
})Use React hooks
import { useQuery, useSyncClient } from "@stratasync/react"
function TodoList() {
const { data: todos } = useQuery("Todo", {
where: (t) => !t.completed,
})
const { client } = useSyncClient()
return (
<ul>
{todos.map((todo) => (
<li key={todo.id}>{todo.title}</li>
))}
<button onClick={() => client.create("Todo", {
title: "New todo",
completed: false,
})}>
Add
</button>
</ul>
)
}