Watch data changes in real time

React to every insert, update, and delete in your Postgres or SQLite database as it happens. Subscribe to a table through a Live Collection, define a query as a Live View, or configure a Change Stream to choose how Conjoin delivers each change.

Stream one table with no configuration, or take control of every step

Conjoin Live captures every change in your Postgres and SQLite tables and delivers it through Relay, the Conjoin service for jobs, queues, and events, to the clients that subscribe. A Live Collection works with no configuration, while a Live View re-executes a named query when its data changes. For full control over capture, filtering, batching, and delivery, configure a Change Stream.

Stream changes with as much control as you need

Live Collections

When you enable a Live Collection on a table with one API call, Conjoin creates the Change Stream and the Relay broadcast channel for it. On the client, the SDK fetches the first data, opens the WebSocket subscription, applies each change, and reconciles its copy with the server at intervals.

Live Views

Define a named query with joins, filters, and sorting on the server as a Live View. Conjoin re-executes the query whenever a table that it references changes, then pushes the new result to clients only if that result differs from the previous push.

Change Streams

On a Change Stream, you choose which operations Conjoin captures, the payload mode, and how Conjoin delivers the changes through Relay. A payload contains the primary key alone, the new values, or a full diff, depending on the payload mode that you set.

Live Presence

With Live Presence, you can add shared collaboration state to any Live Collection or Live View. Conjoin syncs the JSON state that you declare, such as a cursor position, a viewing status, or a selection highlight, to every connected client. When a client connects, disconnects, or times out, Conjoin sends a join or leave event to the others.

React and vanilla SDKs

In React, the useCollection and useView hooks load the data, manage the subscription, merge incoming changes, and reconcile with the server for the life of the component. For any other JavaScript runtime, the vanilla SDK provides conjoin.collection() and conjoin.view(), which call your onChange callback with each change.

Backpressure and volume control

Conjoin splits a large transaction into small batches, up to the batch size limit of your tier. If replication lag passes the threshold that you set, Conjoin pauses its consumption of the WAL and suspends the affected streams. In a best-effort delivery mode, Conjoin then drops changes and inserts a gap marker, while in a guaranteed mode, it pauses delivery and resumes from the same position.

Flexible delivery routing

Route database changes to a broadcast channel, an event topic, a queue, a pipeline, a search index, or a cache invalidation endpoint. Use broadcast for a frontend that updates as the data changes, and use a queue or a pipeline for background processing.

WAL-level change capture

Conjoin captures Postgres changes through a logical replication slot with the pgoutput plugin, and SQLite changes through WAL hooks. Conjoin sends the changes from both engines into the same streaming pipeline, so you add no triggers or polling to your application.

200ms
Default debounce

Configurable per live view

6+
Delivery modes

Broadcast, events, queues, pipelines, search, cache

0
Config for Live Collections

One API call to enable

Build faster with solutions designed for real-world needs

Build a live dashboard with one React hook

Enable a Live Collection on the table behind the dashboard, then call useCollection in the React component that draws it. The hook opens the WebSocket connection, loads the first rows, and re-renders the component with each update that Conjoin delivers.

Impact

Conjoin pushes each change in the table to the dashboard within milliseconds. Because the SDK also reconnects and reconciles after a dropped connection, you build and maintain no WebSocket server for the dashboard.

Add live presence with a single boolean flag

Add presence: true to a useCollection or useView call, then declare the state that each client shares, such as a cursor position, a selection, or a typing indicator. Conjoin syncs that state across the connected clients and notifies them when someone joins or leaves.

Impact

With one boolean on the hook, your interface can show who else has the same data open and where each of their cursors is. Conjoin hosts the presence state, so you build no presence service of your own.

Keep your search index in sync automatically

Configure a Change Stream in search delivery mode and point it at your Search index. Conjoin applies each row change from the database to the index, with the batching and rate limits that you configure.

Impact

Conjoin updates the index within seconds of each database change, so you maintain no ETL script or cron job to copy the data across.

Push changed rows to clients the moment they change

Conjoin Live captures each change from the write-ahead log, through logical replication on Postgres and WAL hooks on SQLite, and delivers it through Relay. Each client receives only the rows that change, at the time that they change.

Impact

Because Conjoin pushes each change to the client, you can remove the polling loop, along with the repeated queries that it sends to your database. The client shows each change as soon as Conjoin delivers it.

Build your next app on Conjoin

Conjoin will open with a free Build tier, while the pricing page already lists the launch prices for Pro and Business. If you tell us what you're building, we'll talk you through early access.