blog

What Rindle Is For

An honest account of Rindle Cloud — the problems it's shaped for, the ones it isn't, and where the edges are. Written for someone deciding whether to build on it, not to sell them on it.

Matt Wonlaw

Updated July 16, 2026. The original version described Rindle Cloud’s single write master in a way that could be read as serialized write execution. That is no longer accurate. The HCTree master admits multiple transactions concurrently and can execute disjoint work in parallel; it still commits one ordered replication log. This revision separates those two ideas throughout.

This is about Rindle Cloud, not the Rindle engine. Everything below describes the fit profile of a specific deployment topology: one authoritative write-master (rindle-replicator) fanning an ordered change log out to many rindled read followers and client replicas. Rindle Cloud is the managed embodiment of that topology, and it’s the lens this document uses.

rindle itself is just an engine — an embeddable incremental-view-maintenance library. It imposes exactly one real constraint: changes must reach each instance of materialized state as a single, totally-ordered stream (IVM is defined over an ordered sequence of deltas — there has to be a sequencer). But that’s an ordering point, not serialized execution. Rindle Cloud implements it as one durable HCTree write master per database: multiple transactions may be open and executing, while successful commits receive the single order every replica consumes. The client tier already writes non-durably and optimistically and later reconciles against that order. What the engine forbids is divergent, unsequenced change streams racing into the same materialized state — not concurrent transactions. Read this as the canonical worked example of deploying the engine, not the boundary of every topology the embeddable engine could support.

The one-sentence version

Rindle Cloud is a managed sync platform — built on the Rindle IVM engine — for sync-shaped, collaborative applications with bounded live working sets. It keeps each client’s queries continuously and incrementally up to date — and it is honest that reads scale by adding followers, while writes run concurrently inside one master and scale out by sharding.

If that sentence describes your application, Rindle Cloud is likely a very good fit. If your bottleneck is sustained write throughput beyond one logical master, it is not. More cores, engine threads, and HCTree connections raise one master’s ceiling; another master means another shard. The rest of this document explains the boundary precisely enough that you can decide for yourself.

What the engine actually does

At its core Rindle does one thing well: you register a query, you get a materialized view, and that view is maintained incrementally as the underlying data changes. The cost of applying a change is a function of how much changed, not how much data exists. A new row flowing into a 6-thousand-row table and a 120-thousand-row table costs the same to push through a materialized query — single-digit microseconds, flat as the dataset grows. That scale-invariance is the whole point of an IVM engine and the property everything else is built to protect.

The IVM engine runs in the two places that maintain live views, with identical operators and semantics:

  • In the client — a local-first replica that holds the user’s queries as materialized views, applies optimistic writes immediately, and reconciles against the server’s authoritative log.
  • In a rindled read follower — a server-side daemon that holds shared materializations, serves many clients over websockets, and applies a replicated change stream.

The data tier adds a third component with a different job: the write master (rindle-replicator) is the HCTree authority, not another query-serving IVM replica. It accepts concurrent SQL transactions, commits them into one order, and fans that ordered, durable change log out to the followers that maintain views.

The deployment we scale on is the natural consequence: one write-master fans out to many read followers, each serving many client replicas. Writes converge on the master; reads and live subscriptions fan out across the followers and down to the clients.

The scaling model, and the two laws

Everything about where Rindle fits follows from two architectural laws. They are not marketing simplifications, but the capacity of a particular deployment still has to be measured.

Law 1 — Reads scale horizontally.

A read follower does three things that compound well:

  • It deduplicates work. Subscribers asking for the same query share one pipeline and one materialization (MaterializationManager keys by query identity). A thousand users watching the same feed cost one feed’s worth of computation, not a thousand.
  • It stays flat under load. Hydration latency holds constant as the number of distinct materializations grows — the worker pool absorbs the concurrency rather than degrading.
  • Its memory is bounded by working set, not by row count. Materializations keep only primary keys resident and fault the rest of each row from disk on demand, so a broad view costs roughly pk_size × rows of RAM with the body disk-backed — not the full row times the row count.

Need to serve more readers, more subscriptions, or more distinct live queries? Add followers. They each take a copy of the same change log and serve their share of clients. The read plane is horizontal.

Law 2 — Writes scale up within one master, then out by sharding.

There is exactly one write master per logical database. This is deliberate: one commit order is what makes every follower and every client converge without a conflict-resolution protocol. That is an ordering constraint, not a one-request-at-a-time constraint. Followers add no write capacity, but the master uses a pool of HCTree connections and can use multiple execution threads on one machine.

There are three distinct layers:

  • Admission. RINDLE_WRITE_CONNECTIONS controls how many write sessions may be open at once; the default pool has eight connections. An interactive session stays on one connection for life.
  • Execution. Every connection uses BEGIN CONCURRENT. RINDLE_WRITE_THREADS controls how many engine threads execute transaction work (default 1). Raise it with available CPU; disjoint transactions can then execute in parallel.
  • Commit. HCTree validates optimistic transactions and assigns each successful commit the single cid that orders the replication journal. Concurrency before commit does not weaken ordering after it.

Write-only transactions that lose optimistic validation are replayed mechanically, up to a bounded retry limit. A session that already returned read results cannot be safely replayed from captured SQL alone, so the API server re-drives its authoritative mutator. Keyed work uses rendezvous hashing across engine threads to preserve per-key FIFO arrival order; keyless work round-robins. Batching remains an important application-side lever.

The gain is workload-sensitive. Transactions over different tenants, documents, or keys can use the pool well. Transactions that all update the same hot rows will conflict at validation, so increasing thread count eventually adds retries rather than throughput. “Concurrent writes” removes the old global serialization ceiling; it does not repeal contention.

When you outgrow one master’s write rate, the answer is shard by tenant: independent write-masters, each with their own followers. This works beautifully when your data partitions cleanly (per-organization, per-workspace, per-document) and fights you when it doesn’t. That tradeoff is the single most important thing to understand before adopting Rindle Cloud.

What Rindle Cloud is well-formed for

These are the problem classes the architecture is shaped for — where the two laws are advantages, not constraints.

1. Collaborative SaaS over tenant-scoped data. Issue trackers, docs and wikis, project and CRM tools, design and planning apps. Reads and live subscriptions dominate; writes are modest and naturally partition by organization or workspace; every user watches a bounded set of queries over their tenant’s data. This is the bullseye: reads fan out across followers, writes stay within one tenant’s master, and the per-tenant working set fits comfortably in a follower’s deduplicated, disk-backed materializations.

2. Local-first and offline-capable applications. The client is an instance of the engine. It holds the user’s queries as live local views, applies writes optimistically with no round-trip, works offline, and reconciles against the master’s log on reconnect via a monotonic per-client sequence. Apps that want “instant UI, eventual server truth, no manual cache invalidation” get it as a property of the model rather than as glue code they write.

3. Live dashboards and feeds over a bounded dataset. Anything that is “this query, kept fresh on screen” — activity feeds, leaderboards over a scoped set, operational dashboards, presence-adjacent views — is exactly what incremental maintenance is for. The first render hydrates; every subsequent update is a small delta, not a re-query.

4. Replacing a hand-rolled sync stack. Teams that have accreted websockets + polling + a cache + manual invalidation + a reconnect-and-refetch dance are reimplementing a worse version of what Rindle does as one coherent thing. The honest pitch here is consolidation and correctness, not raw speed.

What Rindle Cloud is not for

Equally important, and stated plainly so nobody discovers it in production.

1. Unbounded ingest firehoses. Concurrent writes mean a high request rate is no longer an automatic disqualifier: batched, mostly-disjoint transactions can use multiple HCTree connections and threads. But one master still validates every transaction, assigns every commit order, journals it, and feeds the affected live-query work. Telemetry, clickstream, or IoT workloads whose defining requirement is unbounded sustained ingest into one logical store should use a log or column store designed for that shape — unless a measured Rindle deployment comfortably clears the required rate.

2. Ephemeral high-churn state on the durable path. Cursor positions, “user is typing,” live presence, per-keystroke collaboration. These are high-rate writes whose value is immediacy, not durability. More write concurrency does not make durable journaling useful for them. Route them over a side channel (or a separate, disposable Rindle table) and keep the durable log for state that matters.

3. Analytical / OLAP queries over large cold datasets. Rindle maintains defined queries incrementally; it is not a column store and will not win a full-table aggregate scan over hundreds of millions of cold rows. A bounded, pre-declared aggregate kept live? Yes. Ad-hoc analytics over the whole warehouse? No.

4. Unbounded per-client result sets. The model assumes each client watches bounded queries — paginated, filtered, scoped to a tenant. “Subscribe to every row in the table” is an anti-pattern by construction: it defeats dedup, balloons footprint, and turns the write fan-out multiplier against you. Designing for bounded queries is part of using Rindle Cloud well, not a workaround.

The sharp edges (and what we do about them)

An honest take names the footguns, not just the features.

  • Pagination is the one to respect. A “latest-N” feed (ORDER BY … LIMIT N) is O(1) per write only when the sort column is indexed and the planner has fresh statistics to use that index. Miss either and the engine silently degrades to a full re-sort of the base on every insert — a perf cliff, not a correctness bug, so it hides until you’re under load with a large table. We auto-author the covering index and refresh stats, and we are adding registration-time detection and live full-scan observability so a regression announces itself instead of lurking (tracked as #78).
  • Correlated EXISTS wants statistics. Without ANALYZE, a two-predicate existence probe can mis-plan into an O(n²) hydration; with it, it’s linear. This is now part of standard schema hygiene, applied automatically.
  • The write fan-out multiplier is real. Every committed row is pushed through every live pipeline that reads its table, so a hot table read by many distinct queries pays a multiple on each write. Followers spread this across nodes and dedup collapses identical queries, but a single table read by many distinct live views is genuine work — design your hot paths with that in mind.
  • Concurrency follows the conflict surface. Eight open sessions do not imply an eightfold speedup. Hot keys and overlapping read-modify-write transactions produce OCC retries; disjoint tenant- or document-scoped work benefits most. Watch conflict/re-drive rates, batch related statements, and partition genuinely hot domains before adding threads blindly.
  • You own the schema, so index it. Because you author the tables the engine reads, indexing the columns it sorts and joins on is your lever and your responsibility. Most pathologies above are an un-indexed sort or correlation column.

What we’ve measured, modeled, and not yet proven

The most honest section, because maturity is part of the truth.

  • Measured, on real workloads: scale-invariant incremental push across the query ladder; flat hydration as materializations grow; and linear materialization footprint. These are committed as regression-gated baselines.
  • Correctness-tested, not yet a production capacity claim: concurrent HCTree ingress has coverage for pooled sessions, OCC retry/re-drive, per-key ordering, and engine-thread failure. Those tests establish behavior, not a universal transactions-per-second number.
  • Modeled, not yet run at scale: the per-customer capacity figures (how many users a blog / forum / CMS / chat shape supports) come from measured unit economics solved through a capacity model on a single box. They are calibrated, not multi-node production runs.
  • Still in flight: some of the footprint-reduction and pagination-observability work described above is not yet complete.
  • Not yet measured: the production throughput curve across connection count, execution threads, transaction overlap, and storage; the true per-follower subscriber ceiling beyond ~1k connections (our single-process test harness hits a file-descriptor wall first, not an engine wall), and end-to-end numbers for a large many-follower fleet. We quote the conservative single-node numbers and say so.

We would rather tell you which line an estimate sits on than blur them together.

Bottom line

Reach for Rindle Cloud when your application is sync-shaped over a bounded working set — collaborative SaaS, local-first tools, live scoped dashboards — and you want every client’s view to stay incrementally fresh without building a sync layer by hand. Read-heavy applications remain the clearest fit, but authoritative writes no longer queue behind one globally serialized executor: disjoint work can run concurrently inside the master. The architecture works best when writes have a natural tenant, document, or key partition and reads scale independently across followers.

Look elsewhere when your defining constraint is sustained write throughput beyond one tuned master that will not shard, a hot shared-key workload whose transactions continually conflict, or ad-hoc analytics over large cold data. Those are real workloads; they are simply not the shape this engine is for, and we would rather say so up front than have you find the wall yourself.