Skip to content

Data Flow Analysis

The data flow analyzer builds a graph of value and service dependencies between steps in your Effect program. It tracks which steps produce values, which steps consume them, and identifies issues like undefined reads or duplicate writes.

import { analyze, buildDataFlowGraph } from "effect-analyzer/analysis"
import { Effect } from "effect"
const ir = await Effect.runPromise(analyze("./src/transfer.ts").single)
const graph = buildDataFlowGraph(ir)
console.log(graph.nodes.length) // Number of data flow nodes
console.log(graph.edges.length) // Number of dependency edges
console.log(graph.undefinedReads) // Reads with no matching producer
console.log(graph.duplicateWrites) // Keys written by multiple steps

The DataFlowGraph contains:

Field Type Description
nodes DataFlowNode[] One node per effect step
edges DataFlowEdge[] Edges from producer to consumer
producedKeys Set<string> All keys that have a producer
undefinedReads UndefinedRead[] Reads where no producer was found
duplicateWrites DuplicateWrite[] Keys written by more than one step

Each DataFlowNode records:

Field Type Description
id string Node identifier (matches IR node ID)
name string | undefined Human-readable step name
writes string | undefined The success type this step produces
reads string[] Service IDs this step reads from Context

Find which steps produce or consume a given key:

import { getProducers, getConsumers } from "effect-analyzer/analysis"
// Who produces the "balance" value?
const producers = getProducers(graph, "balance")
// Who consumes "AccountService"?
const consumers = getConsumers(graph, "AccountService")

Trace the full dependency chain for a node:

import { getTransitiveDependencies } from "effect-analyzer/analysis"
const deps = getTransitiveDependencies(graph, "step-4")
// All nodes that step-4 transitively depends on

Detect circular dependencies in the data flow:

import { findCycles } from "effect-analyzer/analysis"
const cycles = findCycles(graph)
if (cycles.length > 0) {
console.log("Circular dependencies found:", cycles)
}

Run a comprehensive validation that checks for undefined reads, duplicate writes, and other issues:

import { validateDataFlow } from "effect-analyzer/analysis"
const validation = validateDataFlow(graph)
console.log(validation.undefinedReads) // Reads with no producer
console.log(validation.duplicateWrites) // Keys with multiple producers

Get the topological order of data flow nodes - the order in which they must execute based on their dependencies:

import { getDataFlowOrder } from "effect-analyzer/analysis"
const order = getDataFlowOrder(graph)
// Returns node IDs in dependency-respecting order

Render the data flow as a Mermaid diagram:

Terminal window
npx effect-analyze ./src/transfer.ts --format mermaid-dataflow
import { buildDataFlowGraph, renderDataFlowMermaid } from "effect-analyzer/diagram"
const graph = buildDataFlowGraph(ir)
const diagram = renderDataFlowMermaid(graph)
console.log(diagram)

The diagram shows nodes as boxes with their produced types, and edges indicating which values flow between steps.