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"
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:

FieldTypeDescription
nodesDataFlowNode[]One node per effect step
edgesDataFlowEdge[]Edges from producer to consumer
producedKeysSet<string>All keys that have a producer
undefinedReadsUndefinedRead[]Reads where no producer was found
duplicateWritesDuplicateWrite[]Keys written by more than one step

Each DataFlowNode records:

FieldTypeDescription
idstringNode identifier (matches IR node ID)
namestring | undefinedHuman-readable step name
writesstring | undefinedThe success type this step produces
readsstring[]Service IDs this step reads from Context

Find which steps produce or consume a given key:

import { getProducers, getConsumers } from "effect-analyzer"
// 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"
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"
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"
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"
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"
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.