Real-Time Reactivity
The migration is complete. The app reads and writes through Convex. But we have not yet covered real-time sync, which Convex provides without any extra work.
The Demo
Try this:
- Open the kanban board in two browser tabs (or two different browsers)
- In one tab, add a task
- Watch the other tab. The task appears instantly.
- Move a task in one tab. It moves in the other tab too.
- Delete a task. It is gone from both.
There is no polling here, and no manual refetching, and we did not write any extra code for it. This works because of how Convex is designed.
How It Works
When your component calls useQuery(api.tasks.list), here is what happens behind the scenes:
Browser A Convex Cloud Browser B
│ │ │
├── subscribe(tasks.list) ──▶│◀── subscribe(tasks.list) ─────┤
│ │ │
│◀── initial results ────────│──── initial results ─────────▶│
│ │ │
├── mutation(create) ───────▶│ │
│ (task inserted) │
│ │ │
│ (query re-executed) │ (query re-executed) │
│◀── updated results ────────│──── updated results ─────────▶│
│ │ │
-
The
ConvexReactClientopens a persistent WebSocket connection to the Convex cloud when the app starts. -
Each
useQuerycall creates a subscription: the client requests the results oftasks.listand asks to be notified when they change. -
Convex tracks which data each query reads, including that
tasks.listreads from thetaskstable. -
When a mutation modifies the
taskstable, Convex automatically identifies all active subscriptions that might be affected. -
It re-executes those queries on the server and pushes the new results to every connected client.
-
The
useQueryhook receives the new data and the React component re-renders.
This all happens in milliseconds. The client does not need to know about cache invalidation, stale data, or when to refetch. Convex handles it.
Comparing to Previous Approaches
Think about how we handled data in earlier tutorials:
- localStorage (KudoBoard): data exists only in one browser. No sharing, no sync.
- useEffect + fetch (Covid Dashboard): data is fetched once on mount. To see updates, you would need to manually refetch or set up polling.
- TanStack Query (Shopping Cart): better caching and refetching, but you would still need to invalidate the cache or poll for changes to see updates from other users.
In Convex, real-time sync is the default behavior. You do not opt into it. You would have to opt out of it, and that is almost never what you want.
What This Means for Users
Real-time reactivity enables features that would be complex to build with traditional REST APIs:
- Collaboration — multiple people working on the same board, seeing each other’s changes instantly
- Live dashboards — data updates without the user pressing a refresh button
- Consistent state — no stale data, no “refresh to see latest changes”
For our kanban board, it means that if two teammates are looking at the same board, they always see the same tasks in the same columns. There are no sync issues and no conflicts, and we did not write any extra code to get that.