Electric Circuits is a new primitive that turns any static database query into a live version of it. Declare any query in your application and maintain its result set updated with changes on the database in realtime.
Electric Circuits is an experimental prototype. It applies the theory of incremental view maintenance, and uses Durable Streams to deliver data at scale. In this blogpost we explain how we've built it and what it delivers.
✨ Research preview
Electric Circuits is a research preview. Checkout the repository and try the circuit visualizer.
From static to live queries
Applications and agents need live data. Getting there from a static query means building machinery around it. Fetch a snapshot. Poll for changes and handle cache invalidation. This is difficult to get right and in the end your application is still laggy due to the amount of hops your data has to go through.
The alternative is a reactive model: push changes to clients the moment the result set of the query in the database changes. Now the backend has to match each change to the queries it affects, keep pace with the database's write rate, and fan every change out to all the clients subscribed to it.
Simple queries like row filters are extremely scalable, but more complex queries like joins, subqueries or aggregations require internal state to decide whether a query is affected by a change. Internal state is typically attached to each client's subscription, which makes it hard to scale.
Electric Circuits
An Electric Circuit maintains a SQL query as an incremental computation graph. Electric Circuits uses DBSP to build the graphs. DBSP can express full relational algebra and therefore can handle any SQL query.
We tail Postgres logical replication to feed data into the graoh. Changes are threaded through the graph and fanned out to live queries they affect. Live queries are backed by Durable Streams. Connected clients receive changes immediately over SSE or long-polling. Otherwise, they can resume the stream from the last offset they've seen to catch up or start from the beginning.
In Electric Circuits — as in any incremental computation engine — a query is never re-executed against the full database. The work is proportional to the size of the changes passing through the graph, not to the size of the database.
Materialize and Feldera have specialized this class of engine for data warehouses, where re-running queries over large data sets on every change is prohibitively expensive. Electric Circuits builds on the same technology to provide reactive state in applications.
How it work
DBSP represents data as Z-sets — collections where every row carries a signed weight. A table is a Z-set with every row at weight +1; a change is a Z-set too — a small one, a delta: an insert is a row at +1, a delete the same row at −1, an update is both at once. A row belongs to a collection if the weight is positive.
Every SQL statement can be expressed as a relational algebra expression. In the compilation step we translate a statement into a DBSP circuit that holds the computation of the result set of that expression.
Nodes in a circuit are shared across users, therefore identical queries collapse into one: the same table, predicate, and projection resolve to a single circuit and a single output stream. This is what enable state deduplication and the system to scale the number of live queries gracefully.
An example
Here is a query for retrieving issues for all projects a user is member of_
SELECT * FROM issues
WHERE project_id IN
(SELECT project_id FROM project_members WHERE user_id = 42)This query is compiled into the following circuit:
Each source table feeds in its change stream (Δ): one for issues, one for project_members. The subquery runs along the project_members branch: a filter (σ) keeps only user 42's memberships, and a distinct (δ) maintains the inner set — the project ids user 42 belongs to, a handful of keys, never any issues. That inner set is the only state the pipeline keeps.
Every issues change meets that inner set at a membership join (⋈): if the issue's project_id is in the set, it belongs in the result. A projection (π) turns it into a change envelope, appended to the query's stream (the sink). Add user 42 to a project and its id enters the inner set at δ; remove them and it leaves — and the join re-decides who sees what, incrementally, without ever re-running the query.
So the pipeline holds only keys — the inner set of project ids and the membership decision — never a copy of your issues.
Circuits hold no data
Circuits hold only data keys. Rows live in the server and fetched to server initial queries or when the visibility of data changes for a query (e.g. the subqueries example discussed above). Postgres remains the source of truth and the circuits memory efficient. The trade is slightly higher latency of querying Postgres to get data when is missing for an initial query or handle membership change, but that doesn't affect established live queries that are in the live streaming phase.
Reactivity end-to-end
Reactivity doesn't stop at the server. When data is delivered into the client, it can be piped to TanStack DB where last-mile filters and further live queries run client-side, without another round trip. The server maintains what's shared between clients; the client computes what's personal to one. One reactive model, all the way from the WAL to the UI.
Electric circuits with a rich queries can reduce the gap between the data that is synced to the client and the data that the client actually needs.
The database, inside out
StreamDB turned a Durable Stream into a reactive database: declare a schema and the stream materializes into typed collections that stay current as events arrive. What it didn't give you was a way to decide what goes into the stream in the first place. Filtering changes into the streams that need them was application code — written by hand, one path per query, and maintained by you. Electric Circuits makes it expressible: the query statement defines the stream. Write SQL, and the circuit routes each change to the streams whose results it affects. Fetching, polling, invalidating, routing — all of it was code you wrote to keep a static query current. With Circuits, that code is the query.
What we've landed (TODO)
- Expressive queries maintained server-side: subquery membership and aggregations, on one engine.
- Runs production Electric's own conformance oracle; a sibling suite covers concurrency, engine restarts and resume.
- Server-side aggregations:
COUNT(*)per group is circuit-maintained; SUM/AVG/MIN/MAX are incremental folds, no rescans. - Run it yourself: interactive circuit visualizer and a LinearLite demo.
The data layer for AI-era software (TODO)
- Agents don't sit on connection pools; they read and write logs.
- Library mode is already a second producer — this is demonstrated, not roadmap.
- Circuits make accumulated agent state, and your database, queryable and live.
Try it now
- Go break it: create a query, write to Postgres, watch the change propagate through the circuit down to the stream.
- No hosted instance — clone the repo and run LinearLite and the visualizer against your own Postgres.
- CTA buttons: repo · demo · Discord.

