Skip to content

Introduction

effect-analyzer is a static analysis toolkit for Effect programs. It parses your TypeScript source code using ts-morph, extracts a typed intermediate representation (IR) of every Effect program it finds, and renders that IR into diagrams, metrics, reports, and structured data - all without executing your code.

Think of it as a compiler front-end for Effect workflows. Where a compiler turns source into machine code, effect-analyzer turns source into understanding.

The fastest way to see that value is not the CLI output. It is the live browser playground and the interactive HTML viewer. Those are the strongest product demos because they let people see the structure immediately and share it with others.

The analyzer recognizes a broad set of Effect patterns and control-flow constructs:

  • Generators - Effect.gen functions with yield* bindings
  • Pipes - Effect.pipe and .pipe() chains
  • Services - Context.Tag dependencies and Layer providers
  • Layers - Layer.effect, Layer.provide, Layer.merge compositions
  • Error handlers - Effect.catchAll, Effect.catchTag, Effect.catchTags
  • Parallel & race - Effect.all with concurrency, Effect.race
  • Retry & timeout - Effect.retry, Effect.timeout, schedule-based policies
  • Streams - Stream pipelines and operators
  • Fibers - Effect.fork, Fiber.join, Fiber.interrupt
  • Conditionals & loops - Effect.if, Effect.loop, Effect.iterate
  • Cause & Exit - Cause.match, Exit.match patterns
  • Resources - Effect.acquireRelease, Scope-managed lifecycles

Every detected program is converted into a StaticEffectIR - a tree of typed nodes that captures the structure of your Effect code. Each node records its type (effect, generator, parallel, error-handler, etc.), its children, its service dependencies, its error types, and its source location.

This IR is the foundation for everything the tool produces. Renderers transform it into Mermaid diagrams. Analyzers compute complexity metrics from it. Diff tools compare two IRs to find structural changes.

TypeScript Source → ts-morph AST → Effect IR → Output

Because the IR is a plain data structure, you can also consume it directly in your own tooling via the library API.

  • Developers exploring unfamiliar Effect codebases or reviewing pull requests
  • Teams generating living documentation for complex workflows
  • CI/CD pipelines tracking complexity regressions and structural changes over time
  • Tooling authors building custom analysis, linting, or visualization on top of the structured IR

effect-analyzer ships with over 25 output formats:

  • 15 Mermaid diagram types - railway, flowchart, service maps, error flows, concurrency views, layer graphs, retry timelines, and more
  • Structured data - JSON IR, complexity stats, plain-English explanations, dependency matrices
  • Analysis reports - execution paths, test coverage matrices, data-flow graphs, error propagation analysis
  • Project tools - coverage audits, semantic diffs, migration assistant, strict diagnostics
  • Interactive HTML - a self-contained viewer with search, filtering, path explorer, and 6 color themes

The docs now use committed fixtures instead of screenshots, so the examples below are real analyzer output you can reproduce locally.

Example fixture: packages/effect-analyzer/src/__fixtures__/docs/transfer-workflow.ts

$ npx effect-analyze ./src/__fixtures__/docs/transfer-workflow.ts --format explain
transferWorkflow (generator):
1. Yields accounts <- AccountService
2. Yields audit <- AuditLog
3. Yields balance <- accounts.getBalance
4. If balance < amount:
Returns:
Calls fail - constructor
5. Calls accounts.debit
6. Calls accounts.credit
7. Calls audit.record
Services required: AccountService, AuditLog
Error paths: AccountNotFoundError, InsufficientFundsError
Concurrency: sequential (no parallelism)

Project-wide audit example: packages/effect-analyzer/src/__fixtures__/docs/audit

$ npx effect-analyze ./src/__fixtures__/docs/audit --coverage-audit
Discovered: 4
Analyzed: 2
Zero programs: 2
Suspicious zeros: 0
Failed: 0
Coverage: 50.0%
Analyzable coverage: 100.0%
Unknown node rate: 0.00%
Zero categories: barrel/index=1, config/build=0, test/dtslint=0, type-only=0, suspicious=0, other=1

Diff example: packages/effect-analyzer/src/__fixtures__/docs/send-money-before.ts vs packages/effect-analyzer/src/__fixtures__/docs/send-money-after.ts

$ npx effect-analyze ./src/__fixtures__/docs/send-money-before.ts ./src/__fixtures__/docs/send-money-after.ts --diff
# Effect Program Diff: sendMoney -> sendMoney
Added: 8
Removed: 1
Unchanged: 7
Structural changes: 1
- transfers.execute
+ FraudScreening
+ Notifications
+ fraud.screen
+ notifications.sendConfirmation
Structural Changes
- retry block added

Install the package and run your first analysis in the Quick Start guide.