Skip to main content
Refactron is built to stay fast on real codebases — not just toy fixtures. The numbers below are reproducible benchmarks against synthetic trees that mix Python and TypeScript files sprinkled with every shipped transform pattern.

Headline numbers

analyze on an Apple M2 (8 cores, 8 GB RAM, Node 24, Refactron 0.2.x):
Tree sizeFilesMedianMinMax
10k LOC4481.21s1.19s1.31s
100k LOC4,46511.13s10.56s13.14s
Validated end-to-end on Ansible (playground/ansible, ~100k LOC, 4,465 files) — every shipped transform runs through analyzerun --dry-runrun --apply without timing out or running out of memory.

Full pipeline (analyze → plan → apply with verification)

Against fixtures/python-legacy-mini (9 files, 189 LOC, real pytest suite):
StepMedianMinMax
analyze0.16s0.16s0.19s
run --dry-run1.70s1.66s1.87s
run --apply (3 gates + atomic write)3.38s3.27s3.72s
The --apply cost is dominated by the test gate — Refactron runs your full project test suite inside a shadow tree. On larger projects that figure scales with your suite’s runtime, not Refactron’s.

Methodology

  • 1 warm-up run per command (discarded), then 5 measured runs.
  • Wall-clock seconds via /usr/bin/time -p.
  • Fresh fixture copy per iteration of --apply (it mutates the tree).
  • Report median (middle of 5), min, max.
Hardware for the headline numbers:
  • Apple M2 · 8 physical cores · 8 GB RAM · Darwin 25.4 arm64
  • Node v24 · npm 11

Reproduce it yourself

# Generate a synthetic 10k-LOC tree mixing Python + TypeScript
# with every Refactron transform pattern sprinkled in.
npx tsx bench/gen-fixture.ts 10000 bench/10k-loc

# Time analyze.
time node dist/cli/index.js analyze bench/10k-loc

# Time the full pipeline against a real fixture with a test suite.
bash bench/run-pipeline-bench.sh

# Cleanup.
rm -rf bench/10k-loc

Performance targets (v0.2 release gate)

Tree sizeTargetCurrent
10k LOCanalyze < 6s1.21s
100k LOCanalyze < 60s11.13s
500k LOCanalyze < 5minLocal-only, see notes
100k LOC + run --apply< 5min including test gateDominated by your suite
The 500k-LOC tree generation requires ~25 MB of disk and ~30s wall-clock; skipped in CI, run locally before each release.

Where the time goes

The dominant costs, in order:
  1. Python sidecar spawnchild_process.spawn('python3', [sidecar, file]) for every Python file × every Python transform. Spawn cost is ~30ms per invocation. Mitigated by per-file transform composition (one spawn covers all transforms for a file).
  2. Tree-sitter / ts-morph parsing — re-parsing the same file for each detector. The detector layer caches the tree per file per command.
  3. ts-morph project initialization — building a Project over a large TS codebase is expensive; built once per command, reused across transforms.
  4. Atomic batch writes — fsync per file. Amortizes well on batches > 100 files.
If you observe a regression against these numbers, file an issue with the output of bash bench/run-bench.sh and your hardware.

Concurrency

refactron analyze and run --dry-run are CPU-bound on the parser; the engine fan-outs at the per-file boundary up to min(16, cpu_cores - 2) concurrent workers. Set REFACTRON_CONCURRENCY=<n> to override. run --apply runs the verifier sequentially per gate — syntax and imports concurrently within their gates, tests serially (your suite owns its own parallelism).