← Back

Incremental Computation with Jane Street's Library: A Practical Guide

Learn how Jane Street's Incremental library implements efficient incremental computation, how it parallels JavaScript signals, and how to apply its principles in your projects.

The core idea behind incremental computation is simple: recompute only when dependencies change. Spreadsheets do it. Jane Street's Incremental library does it for OCaml programs. It's a production-tested tool that maintains a directed acyclic graph of values and propagates changes efficiently. If you work with derived state, understanding this pattern will make your systems faster and more predictable.

What Is the Incremental Library?

Incremental is an OCaml library for efficient incremental computation. You define a graph of nodes where inputs can change, and the library automatically recomputes only those nodes whose dependencies actually changed. It uses height-based topological ordering to minimize work and supports batching via stabilize—a method that flushes pending updates in one go.

The library is battle-tested at Jane Street, a quantitative trading firm, where every microsecond matters in pricing models. The design principles align with what reactive frameworks now call signals or dataflow graphs, but implemented with a focus on strict efficiency and predictability.

Why Developers Are Paying Attention

The Hacker News thread buzzing around Incremental taps into a conversation many developers are having: how to manage reactive updates at scale. One commenter noted the resemblance to JavaScript signals, with a proposal for standardization. Another praised Jane Street for packaging research ideas into usable libraries.

The library codifies a pattern many have implemented ad hoc, and it does so with rigorous documentation. The comparison to signals (as in SolidJS, Vue, and the TC39 proposal) is spot-on: similar graph-based change propagation, but with different tradeoffs around push vs. pull and stabilization.

Key Takeaways for Efficient Reactive Programming

Incremental isn't revolutionary—it's a very good implementation of a well-known algorithm. But that's exactly why it matters. Too many projects reinvent incremental recomputation as an afterthought, ending up with brittle solutions that leak memory or glitch. Jane Street shows that treating incremental computation as a library concern, not a framework feature, leads to cleaner abstractions. Here are concrete lessons:

1. Distinguish Between Push and Pull

Most developers default to push: when an input changes, recompute all dependents immediately. That can cause redundant work. Incremental uses pull via stabilize. For a UI layer, you might batch mutations and only recompute before render.

// Pseudocode: pull-based reactive system
let a = mutable(5);
let b = mutable(10);
let sum = computed(() => a.value + b.value);
// after mutations
stabilize(); // recompute sum only once

2. Topological Ordering Matters

If you can compute a node's height (depth in the dependency DAG), you can schedule updates without scanning all nodes. This is similar to how SolidJS 2.0's height-based algorithm works. The snippet below shows the idea:

// Height-based update propagation (simplified)
function update(node) {
  if (node.height > currentHeight) return;
  node.recompute();
  node.consumers.forEach(child => {
    if (child.height > node.height) update(child);
  });
}

3. Batching Is Not Optional

Without batching, every mutation triggers a cascade. Use a transaction or stabilize equivalent. This is what databases do, and your in-memory computations should too.

4. Look at Existing Implementations Before Rolling Your Own

The Javelin library in Clojure takes a similar cell-oriented approach. The TC39 signals proposal is aiming to standardize this pattern across JavaScript. If you need incremental computation today, consider adopting those primitives instead of writing ad-hoc listeners.

Pull vs Push: The Stabilize Method

stabilize is a standout feature: it decouples change notification from computation. You mutate inputs freely, then call stabilize to bring the system to a consistent state. This pull-based approach is fundamentally different from eager push-based observables (like RxJS). It gives you control over when work happens, which is critical for performance in hot paths. Height-based propagation ensures that nodes are updated in the correct order, avoiding O(n²) cascading seen in naive dependency systems.

When to Use Incremental Computation

If you build real-time dashboards, compilers, games, or any application with derived state that changes frequently, Incremental and its kin offer a proven pattern to avoid recomputation overhead and bugs. If you're writing a simple CRUD app with no complex state derivation, you can skip it. But even then, understanding pull-based incremental computation will make you a better architect. Jane Street's library is a clear, documented reference—read its design docs, even if you never write a line of OCaml.