ReScript HomeReScript Home
DocsPlaygroundBlogCommunityPackages
  • Playground
  • Blog
  • Community
  • Packages
  • X
  • Bluesky
  • GitHub
  • Forum
Dec 28, 2025

Real-Time Analysis is Coming to ReScript

ReScript's static analyzer is going reactive. Dead code detection that updates instantly as you edit, powered by novel reactive combinators.

ReScript Team
Core Development

Introduction

Imagine editing a ReScript file and seeing dead code warnings update almost immediately as you work. No waiting for a full re-analysis command. Just continuous feedback about which parts of your code are actually used.

This is what we're bringing to ReScript.

The static analyzer that powers dead code detection is being rebuilt on a reactive foundation. When you add a reference to a function, the "unused" warning vanishes quickly. When you remove the last use of a module, the dead code warning appears right away. The analysis stays in sync with your code, updating in real time.

Why This Matters

Traditional static analyzers work in batch mode: gather all files, analyze everything, report results. This works fine when you run analysis as a CI check or a manual command. But it's not what you want when you're actively editing code.

Batch analysis has an awkward tradeoff:

  • Run it rarely and feedback comes too late to be useful

  • Run it often and you're constantly waiting

What developers actually want is continuous feedback that keeps up with their typing speed. That's exactly what reactive analysis provides.

The Reactive Approach

Instead of re-analyzing your entire project on every change, the reactive analyzer represents the analysis as a computation graph. Each piece of data—declarations, references, liveness information—flows through this graph. When a file changes, only the affected parts of the graph recompute.

The result: analysis that completes in milliseconds for typical edits, even in large codebases.

A Concrete Update Flow

Suppose you have a call graph where main calls helper, and helper calls format and validate. In your edit, validate starts calling old.

With batch analysis, the analyzer scans everything again. With reactive analysis:

  1. The edited .cmt updates — FlatMap extracts the new reference. The compiler already resolved it: the ref knows its target (old) and its source location (inside validate)

  2. Join maps that source position to its containing declaration, producing a new graph edge: validate → old

  3. Fixpoint propagates reachability from roots (main) along edges — old now becomes reachable and enters the live set

  4. A final Classify step (a join of declarations with the live set) marks old as live — so its dead-code warning disappears

The rest of the project graph stays untouched.

A Glimpse Under the Hood

Here is a simplified view of the reactive dead code pipeline:

Simplified reactive dead code pipeline

The analysis pipeline is built from composable operators:

  • Sources hold the raw data from your .cmt files

  • FlatMap extracts declarations, references, and annotations from each file's data

  • Union merges collections — for example, combining value references, type references, and exception references into a unified set

  • Join maps data across collections — for example, mapping each reference to the declaration that contains it, or partitioning declarations into dead and live using the fixpoint result

  • Fixpoint computes transitive reachability — starting from root declarations (entry points, annotated @live, or externally referenced), following edges to find everything that's live

That last one, fixpoint, is particularly interesting. Dead code detection needs to know which declarations are reachable from your entry points. This is a classic graph traversal—but doing it incrementally is hard. When you add one edge to a graph, how do you efficiently update the set of reachable nodes without recomputing from scratch?

In the running example above, only one new edge (validate → old) is added, and fixpoint propagates liveness from that delta.

Fixpoint: incremental reachability

The reactive fixpoint operator solves exactly this problem. It takes a set of roots and a set of edges, and maintains the full reachable set. In this example, once old becomes reachable through validate, fixpoint only propagates through neighbors affected by that new edge, without revisiting unrelated parts of the graph. This is what makes the analysis fast enough for real-time use.

Glitch-Free by Design

There's a subtle correctness issue with reactive systems: glitches. If node A depends on both B and C, and both B and C update, node A might briefly see an inconsistent state—B's new value with C's old value, or vice versa.

For analysis, glitches mean incorrect results. A function might briefly appear dead because the reference to it hasn't propagated yet, even though it's actually used.

The reactive scheduler prevents this with a simple principle: accumulate, then propagate. All updates at each level of the graph are collected before any downstream nodes run. Nodes process in topological order, wave by wave. The analysis never sees partial updates.

What's Shipping

The reactive analysis infrastructure is landing now. Here's what it enables:

For Developers

  • Editor integration: Available now in the latest extension, with reactive dead code updates during active development

  • Monorepo support: The analyzer now works correctly in monorepo setups, running from the workspace root with proper binary lookup

  • Faster CI analysis: Incremental runs are dramatically faster than full runs

  • Immediate feedback loop: See the impact of your changes instantly

For Tooling Authors

The reactive primitives are general-purpose. The same infrastructure that powers dead code detection can express other analyses:

  • Dependency graph visualization

  • Unused export detection

  • Reference counting and hotspot identification

  • Custom project-specific checks

The Road Ahead

This is the beginning of a larger shift. The same reactive foundation will extend to other parts of the editor experience:

  • Type checking: Incremental type feedback without waiting for builds

  • Navigation: Jump-to-definition that stays accurate as files change

  • Refactoring: Real-time previews of rename and move operations

The goal is an editor experience where the tooling keeps up with you—no waiting, no stale results, just continuous assistance.

Try It Today

Requirements:

Reactive analysis is a newer capability of Editor Code Analysis and requires a newer extension version.

  • ReScript compiler >= 12.1.0

  • VSCode or Cursor with rescript-vscode extension >= 1.73.9 (pre-release)

  1. Start the build watcher (accept the prompt when opening a ReScript file, or run "ReScript: Start Build")

  2. Run "ReScript: Start Code Analyzer"

Dead code warnings appear in your editor and update reactively while you develop (currently driven by save/build updates). For configuration options and usage details, see the Dead Code Analysis guide.

Acknowledgments

The reactive primitives are based on work by SkipLabs. Their reactive collections library provides the foundation for glitch-free, incremental computation that makes real-time analysis possible.


We're excited to bring this to the ReScript community. Static analysis that runs continuously, in the background, without you having to think about it—that's the experience we're building toward.

Stay tuned for broader reactive tooling updates. And as always, we welcome feedback on GitHub and on the forum.

Want to read more?
Back to Overview

© 2026 The ReScript Project

About
  • Community
  • ReScript Association
Find us on