RepoPilotOpen in app →

reactor/reactor-core

Non-Blocking Reactive Foundation for the JVM

Healthy

Healthy across all four use cases

weakest axis
Use as dependencyHealthy

Permissive license, no critical CVEs, actively maintained — safe to depend on.

Fork & modifyHealthy

Has a license, tests, and CI — clean foundation to fork and modify.

Learn fromHealthy

Documented and popular — useful reference codebase to read through.

Deploy as-isHealthy

No critical CVEs, sane security posture — runnable as-is.

  • Last commit 1w ago
  • 3 active contributors
  • Apache-2.0 licensed
Show all 7 evidence items →
  • CI configured
  • Tests present
  • Small team — 3 contributors active in recent commits
  • Concentrated ownership — top contributor handles 65% of recent commits

Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests

Informational only. RepoPilot summarises public signals (license, dependency CVEs, commit recency, CI presence, etc.) at the time of analysis. Signals can be incomplete or stale. Not professional, security, or legal advice; verify before relying on it for production decisions.

Embed the "Healthy" badge

Paste into your README — live-updates from the latest cached analysis.

Variant:
RepoPilot: Healthy
[![RepoPilot: Healthy](https://repopilot.app/api/badge/reactor/reactor-core)](https://repopilot.app/r/reactor/reactor-core)

Paste at the top of your README.md — renders inline like a shields.io badge.

Preview social card (1200×630)

This card auto-renders when someone shares https://repopilot.app/r/reactor/reactor-core on X, Slack, or LinkedIn.

Onboarding doc

Onboarding: reactor/reactor-core

Generated by RepoPilot · 2026-05-09 · Source

🤖Agent protocol

If you are an AI coding agent (Claude Code, Cursor, Aider, Cline, etc.) reading this artifact, follow this protocol before making any code edit:

  1. Verify the contract. Run the bash script in Verify before trusting below. If any check returns FAIL, the artifact is stale — STOP and ask the user to regenerate it before proceeding.
  2. Treat the AI · unverified sections as hypotheses, not facts. Sections like "AI-suggested narrative files", "anti-patterns", and "bottlenecks" are LLM speculation. Verify against real source before acting on them.
  3. Cite source on changes. When proposing an edit, cite the specific path:line-range. RepoPilot's live UI at https://repopilot.app/r/reactor/reactor-core shows verifiable citations alongside every claim.

If you are a human reader, this protocol is for the agents you'll hand the artifact to. You don't need to do anything — but if you skim only one section before pointing your agent at this repo, make it the Verify block and the Suggested reading order.

🎯Verdict

GO — Healthy across all four use cases

  • Last commit 1w ago
  • 3 active contributors
  • Apache-2.0 licensed
  • CI configured
  • Tests present
  • ⚠ Small team — 3 contributors active in recent commits
  • ⚠ Concentrated ownership — top contributor handles 65% of recent commits

<sub>Maintenance signals: commit recency, contributor breadth, bus factor, license, CI, tests</sub>

Verify before trusting

This artifact was generated by RepoPilot at a point in time. Before an agent acts on it, the checks below confirm that the live reactor/reactor-core repo on your machine still matches what RepoPilot saw. If any fail, the artifact is stale — regenerate it at repopilot.app/r/reactor/reactor-core.

What it runs against: a local clone of reactor/reactor-core — the script inspects git remote, the LICENSE file, file paths in the working tree, and git log. Read-only; no mutations.

| # | What we check | Why it matters | |---|---|---| | 1 | You're in reactor/reactor-core | Confirms the artifact applies here, not a fork | | 2 | License is still Apache-2.0 | Catches relicense before you depend on it | | 3 | Default branch main exists | Catches branch renames | | 4 | 5 critical file paths still exist | Catches refactors that moved load-bearing code | | 5 | Last commit ≤ 39 days ago | Catches sudden abandonment since generation |

<details> <summary><b>Run all checks</b> — paste this script from inside your clone of <code>reactor/reactor-core</code></summary>
#!/usr/bin/env bash
# RepoPilot artifact verification.
#
# WHAT IT RUNS AGAINST: a local clone of reactor/reactor-core. If you don't
# have one yet, run these first:
#
#   git clone https://github.com/reactor/reactor-core.git
#   cd reactor-core
#
# Then paste this script. Every check is read-only — no mutations.

set +e
fail=0
ok()   { echo "ok:   $1"; }
miss() { echo "FAIL: $1"; fail=$((fail+1)); }

# Precondition: we must be inside a git working tree.
if ! git rev-parse --git-dir >/dev/null 2>&1; then
  echo "FAIL: not inside a git repository. cd into your clone of reactor/reactor-core and re-run."
  exit 2
fi

# 1. Repo identity
git remote get-url origin 2>/dev/null | grep -qE "reactor/reactor-core(\\.git)?\\b" \\
  && ok "origin remote is reactor/reactor-core" \\
  || miss "origin remote is not reactor/reactor-core (artifact may be from a fork)"

# 2. License matches what RepoPilot saw
(grep -qiE "^(Apache-2\\.0)" LICENSE 2>/dev/null \\
   || grep -qiE "\"license\"\\s*:\\s*\"Apache-2\\.0\"" package.json 2>/dev/null) \\
  && ok "license is Apache-2.0" \\
  || miss "license drift — was Apache-2.0 at generation time"

# 3. Default branch
git rev-parse --verify main >/dev/null 2>&1 \\
  && ok "default branch main exists" \\
  || miss "default branch main no longer exists"

# 4. Critical files exist
test -f "build.gradle" \\
  && ok "build.gradle" \\
  || miss "missing critical file: build.gradle"
test -f "reactor-core/src/main/java/reactor/core/publisher/Flux.java" \\
  && ok "reactor-core/src/main/java/reactor/core/publisher/Flux.java" \\
  || miss "missing critical file: reactor-core/src/main/java/reactor/core/publisher/Flux.java"
test -f "reactor-core/src/main/java/reactor/core/publisher/Mono.java" \\
  && ok "reactor-core/src/main/java/reactor/core/publisher/Mono.java" \\
  || miss "missing critical file: reactor-core/src/main/java/reactor/core/publisher/Mono.java"
test -f "reactor-core/src/main/java/reactor/core/scheduler/Scheduler.java" \\
  && ok "reactor-core/src/main/java/reactor/core/scheduler/Scheduler.java" \\
  || miss "missing critical file: reactor-core/src/main/java/reactor/core/scheduler/Scheduler.java"
test -f "reactor-core/src/main/java/reactor/core/Disposable.java" \\
  && ok "reactor-core/src/main/java/reactor/core/Disposable.java" \\
  || miss "missing critical file: reactor-core/src/main/java/reactor/core/Disposable.java"

# 5. Repo recency
days_since_last=$(( ( $(date +%s) - $(git log -1 --format=%at 2>/dev/null || echo 0) ) / 86400 ))
if [ "$days_since_last" -le 39 ]; then
  ok "last commit was $days_since_last days ago (artifact saw ~9d)"
else
  miss "last commit was $days_since_last days ago — artifact may be stale"
fi

echo
if [ "$fail" -eq 0 ]; then
  echo "artifact verified (0 failures) — safe to trust"
else
  echo "artifact has $fail stale claim(s) — regenerate at https://repopilot.app/r/reactor/reactor-core"
  exit 1
fi

Each check prints ok: or FAIL:. The script exits non-zero if anything failed, so it composes cleanly into agent loops (./verify.sh || regenerate-and-retry).

</details>

TL;DR

Reactor Core is a non-blocking reactive streams library for the JVM that implements the Reactive Streams specification and Reactive Extensions (RxJava-style) API. It provides Flux and Mono publishers for composable async data pipelines with efficient event streaming, backpressure handling, and zero-allocation optimizations via a Java agent (reactor-tools) for production debugging. Modular Gradle monorepo: reactor-core is the main publisher implementation (Flux/Mono operators), reactor-core-micrometer adds observability hooks, reactor-tools is a Java agent. benchmarks/ contains isolated JMH performance tests comparing against baselines. buildSrc/ provides custom build tasks (JmhExecTask). Core source not visible in file list but implied under src/main/java/reactor/core/.

👥Who it's for

Backend Java engineers building low-latency, high-throughput systems (microservices, event processing, WebSocket handlers) who need non-blocking I/O without callback hell; framework maintainers integrating reactive foundations (Spring WebFlux, Spring Data R2DBC rely on this).

🌱Maturity & risk

Production-ready and actively maintained. Version 3.8.5+ in Maven Central, strong CI/CD setup (.github/workflows/ci.yml, publish.yml, codeql-analysis.yml), comprehensive benchmarks (benchmarks/ directory with JMH comparisons), and multi-JDK support (8, 9, 21) via Gradle toolchains. Last visible release is recent (3.8.5 mentioned in README).

Low risk for stable features; actively maintained with Reactive Streams compliance. Main complexity: multi-release JAR requirements (needs JDK 8, 9, 21 available—build fails silently if missing). Micrometer observability integration adds observability surface. Single language (Java) keeps dependency surface smaller. Breaking changes rare given 3.x stability commitment.

Active areas of work

Active maintenance of 3.8.x line. GitHub Actions workflows (ci.yml, full.yml, codeql-analysis.yml) run on every commit. Benchmarks are actively maintained—see FluxBufferTimeoutBenchmark, CheckpointBenchmark. Micrometer integration is current (MicrometerMeterListenerConfigurationResolveTagsBenchmark exists). No snapshot of PRs visible, but CI suggests continuous integration.

🚀Get running

Clone and build: git clone https://github.com/reactor/reactor-core.git && cd reactor-core. Ensure JDK 8, 9, and 21 are available (Gradle Toolchain auto-detects via .sdkmanrc). Build: ./gradlew build. Run benchmarks: ./gradlew -p benchmarks jmh. Run tests: ./gradlew test.

Daily commands: No server to start—library only. For JMH benchmarks: ./gradlew -p benchmarks jmh -PjmhInclude=MonoCallableBenchmark. For unit tests: ./gradlew test. For CI/CD locally: .github/setup.sh prepares environment (see .github/workflows/).

🗺️Map of the codebase

  • build.gradle — Root build configuration that defines all module dependencies, publishing strategy, and build plugin management for the entire Reactor Core project.
  • reactor-core/src/main/java/reactor/core/publisher/Flux.java — Primary reactive publisher implementation for multi-element streams; core abstraction used throughout the framework.
  • reactor-core/src/main/java/reactor/core/publisher/Mono.java — Reactive publisher for single-element streams; essential abstraction alongside Flux for the API surface.
  • reactor-core/src/main/java/reactor/core/scheduler/Scheduler.java — Abstract scheduler interface that underpins all concurrency and thread management in Reactor; critical for non-blocking execution.
  • reactor-core/src/main/java/reactor/core/Disposable.java — Resource lifecycle management interface; fundamental to memory safety and cleanup in reactive chains.
  • reactor-core/src/main/java/reactor/core/CorePublisher.java — Internal reactive contract that bridges Reactive Streams Publisher with Reactor internals; all operators implement this.
  • .github/workflows/ci.yml — Continuous integration pipeline definition; establishes test coverage, code quality gates, and release readiness criteria.

🛠️How to make changes

Add a new Flux operator

  1. Create new operator class extending FluxOperator<I, O> in reactor-core/src/main/java/reactor/core/publisher/ (reactor-core/src/main/java/reactor/core/publisher/FluxYourOperator.java)
  2. Implement abstract subscribe(CoreSubscriber<? super O>) with subscription and signal forwarding logic (reactor-core/src/main/java/reactor/core/publisher/FluxYourOperator.java)
  3. Add public factory method on Flux class (e.g., public final <R> Flux<R> yourOperator(...)) delegating to your operator (reactor-core/src/main/java/reactor/core/publisher/Flux.java)
  4. Write tests using StepVerifier in reactor-core/src/test/java/reactor/core/publisher/FluxYourOperatorTest.java (reactor-core/src/test/java/reactor/core/publisher/FluxYourOperatorTest.java)
  5. Add assembly trace support via FluxOnAssembly instrumentation if debugging context is needed (reactor-core/src/main/java/reactor/core/publisher/FluxOnAssembly.java)

Add a new Scheduler implementation

  1. Create new scheduler class implementing Scheduler interface in reactor-core/src/main/java/reactor/core/scheduler/ (reactor-core/src/main/java/reactor/core/scheduler/YourScheduler.java)
  2. Implement createWorker() and schedule(Runnable) with thread lifecycle management (reactor-core/src/main/java/reactor/core/scheduler/YourScheduler.java)
  3. Add static factory method in Schedulers class and register in Schedulers.Factory SPI if applicable (reactor-core/src/main/java/reactor/core/scheduler/Schedulers.java)
  4. Write SchedulerTests extending AbstractSchedulerTest for standard contract verification (reactor-core/src/test/java/reactor/core/scheduler/YourSchedulerTest.java)

Integrate new metrics with Micrometer

  1. Create MicrometerXxxListener extending MicrometerMeterListener in reactor-core-micrometer/src/main/java/reactor/core/observability/micrometer/ (reactor-core-micrometer/src/main/java/reactor/core/observability/micrometer/MicrometerXxxListener.java)
  2. Override onBeforeNext(), onAfterError(), onAfterComplete() hooks to record metrics via MeterRegistry (reactor-core-micrometer/src/main/java/reactor/core/observability/micrometer/MicrometerXxxListener.java)
  3. Register listener in MicrometerMeterListenerConfiguration and add tag extraction logic (reactor-core-micrometer/src/main/java/reactor/core/observability/micrometer/MicrometerMeterListenerConfiguration.java)
  4. Test with MicrometerMeterListenerConfigurationTest verifying metrics are recorded correctly (reactor-core-micrometer/src/test/java/reactor/core/observability/micrometer/MicrometerMeterListenerConfigurationTest.java)

Add a new Context-aware feature

  1. Define your feature's context key using Context.of(key, value) convention (reactor-core/src/main/java/reactor/core/context/Context.java)
  2. Create operator or utility that reads/writes Context via Subscriber.currentContext() (reactor-core/src/main/java/reactor/core/publisher/FluxContextAccess.java)
  3. Ensure context is passed through all intermediate subscribers via CoreSubscriber propagation (reactor-core/src/main/java/reactor/core/CorePublisher.java)
  4. Test context isolation and propagation through nested chains using ContextTest patterns (reactor-core/src/test/java/reactor/core/publisher/FluxYourContextFeatureTest.java)

🔧Why these technologies

  • Reactive Streams specification — Provides standardized async/non-

🪤Traps & gotchas

Multi-JDK requirement is critical: build fails opaquely if JDK 8, 9, or 21 missing—check java -version and $JAVA_HOME before blaming Gradle. Gradle Toolchain auto-detection may fail behind corporate proxies; set toolchain paths manually in gradle.properties if CI works but local build fails. Benchmarks are isolated: benchmarks/ depends on reactor-core and reactor-core-micrometer but uses a configurable baseline (libs.reactor.perfBaseline.core)—changing that affects regression results. No main source visible: actual reactor-core source (Flux, Mono, operators) is in src/main/java/reactor/core/ (not in file list)—assume it exists but recognize this list shows structure, not all content.

🏗️Architecture

💡Concepts to learn

  • reactive-streams/reactive-streams-jvm — Canonical Reactive Streams specification that reactor-core implements; defines Publisher, Subscriber, Subscription, Processor interfaces
  • spring-projects/spring-webflux — Primary consumer of reactor-core; Spring's reactive web framework built entirely on Flux/Mono publishers
  • spring-projects/spring-data-r2dbc — Reactive relational database access using reactor-core; shows how to adapt blocking DB drivers to async Mono/Flux streams
  • micrometer-metrics/micrometer — Observability metrics integration (benchmarks/src/main/java/reactor/core/observability/micrometer/); reactor-core-micrometer module hooks into this
  • ReactiveX/RxJava — Predecessor/inspiration for Reactive Extensions API; reactor-core shares similar operator names (map, filter, flatMap) but with stricter Reactive Streams compliance

🪄PR ideas

To work on one of these in Claude Code or Cursor, paste: Implement the "<title>" PR idea from CLAUDE.md, working through the checklist as the task list.

Add comprehensive JMH benchmark tests for reactor-core-micrometer integration

The benchmarks/src/main/java/reactor/core/observability/micrometer directory only contains MicrometerMeterListenerConfigurationResolveTagsBenchmark.java. For a non-blocking reactive library that emphasizes observability, there's an opportunity to add JMH benchmarks for other critical micrometer integration points such as: timer overhead, counter increments, distribution summaries, and tag resolution performance under load. This directly supports performance validation of the observability features that are core to modern reactive applications.

  • [ ] Review the reactor-core-micrometer module to identify key observability APIs lacking benchmark coverage
  • [ ] Create new JMH benchmark classes for at least 3-4 additional micrometer integration scenarios (e.g., TimerBenchmark, CounterBenchmark, TagResolutionUnderLoadBenchmark)
  • [ ] Place new benchmarks in benchmarks/src/main/java/reactor/core/observability/micrometer/
  • [ ] Verify benchmarks execute successfully with both jmh and jmhBaseline gradle tasks
  • [ ] Document benchmark purpose and measured scenarios in class-level JavaDoc

Add performance regression detection in CI pipeline for JMH benchmarks

The repo has established JMH benchmarks (jmh and jmhBaseline tasks) and a publish.yml workflow, but there's no automated CI workflow that runs benchmarks and detects performance regressions. Adding a GitHub Actions workflow (.github/workflows/) that runs JMH benchmarks on PRs against baseline and posts results would catch performance degradations early, which is critical for a non-blocking reactive foundation library where microseconds matter.

  • [ ] Create .github/workflows/jmh-regression-check.yml that runs on PR events targeting main/release branches
  • [ ] Configure the workflow to execute both jmh and jmhBaseline gradle tasks with consistent JVM settings
  • [ ] Parse and compare JMH JSON output results, calculating percentage differences for each benchmark
  • [ ] Post benchmark results as a GitHub PR comment showing regressions (e.g., >5% slowdown) as warnings/failures
  • [ ] Optionally integrate with a benchmarking service (e.g., JMH-Results) for historical tracking

Add unit tests for scheduler-specific edge cases in BoundedElasticBusyStructureBenchmark reference code

The repo contains benchmarks/src/main/java/reactor/core/scheduler/BoundedElasticBusyStructureBenchmark.java and benchmarks/src/main/java/reactor/core/scheduler/OldBoundedElasticScheduler.java (likely for comparative analysis), but there appear to be no corresponding unit tests in reactor-core's test suite specifically validating the thread-busy detection and queuing behavior under concurrent load. Adding reactor-core/src/test/java/reactor/core/scheduler/BoundedElasticSchedulerEdgeCasesTest.java with tests for busy-state transitions, queue overflow handling, and task rejection scenarios would strengthen the reliability of this critical scheduler component.

  • [ ] Examine reactor-core/src/test/java/reactor/core/scheduler/ to identify gaps in BoundedElasticScheduler test coverage
  • [ ] Create BoundedElasticSchedulerEdgeCasesTest.java with at least 5-7 test methods covering: rapid busy/idle transitions, maximum queue capacity exceeded, rejected task handling, task ordering under contention
  • [ ] Use StepVerifier or similar test utilities consistent with the codebase's testing patterns
  • [ ] Run tests with existing CI to ensure no flakiness
  • [ ] Document expected behavior for each edge case in test JavaDoc

🌿Good first issues

  • Add JMH benchmark for a newly added Flux/Mono operator (e.g., new timeout variant). Template exists in benchmarks/src/main/java/reactor/core/publisher/ (see TracesBenchmark.java)—new contributors can follow that pattern and integrate it into the benchmark matrix.
  • Expand Micrometer observability coverage: MicrometerMeterListenerConfigurationResolveTagsBenchmark exists but benchmarks/src/main/java/reactor/core/observability/micrometer/ may be incomplete. Add benchmarks for tag resolution performance under load or high cardinality scenarios.
  • Document scheduler internals: benchmarks/src/main/java/reactor/core/scheduler/BoundedElasticBusyStructureBenchmark.java and OldBoundedElasticScheduler.java suggest scheduler evolution. Create a detailed comment block in the scheduler package explaining thread pool semantics, backpressure behavior, and when each scheduler (boundedElastic, parallel, immediate) is optimal.

Top contributors

Click to expand

📝Recent commits

Click to expand
  • 83ce2fa — [docs] Polish 4955c4a65 (chemicL)
  • 4955c4a — [docs] Follow-up to #4242 - fix stylesheet (chemicL)
  • b570fcd — [docs] Preserve nullability annotations in Javadoc (#4242) (chemicL)
  • e6831ee — [release] Next development version 3.8.6-SNAPSHOT (violetagg)
  • 35c878d — [release] Prepare and release 3.8.5 (violetagg)
  • f85c7b3 — Merge-ignore release 3.7.18 into 3.8.5 (violetagg)
  • bd7be61 — [release] Next development version 3.7.19-SNAPSHOT (violetagg)
  • 13a3b3b — Depend on Micrometer v1.16.5 (#4238) (violetagg)
  • 2ee0aaf — [release] Prepare and release 3.7.18 (violetagg)
  • da92ed3 — Merge #4232 into 3.8.5 (chemicL)

🔒Security observations

The reactor-core benchmarks build configuration shows generally good security practices with proper dependency management and code quality tooling configured. No critical vulnerabilities detected. Main concerns are medium-severity risk around JMH task argument validation and low-severity issues related to baseline dependency usage and version management. The project uses standard security scanning (CodeQL), DCO checks, and has good governance structure. Recommendations focus on input validation for benchmark execution and stricter dependency version control.

  • Medium · Unrestricted JMH Task Configuration — benchmarks/build.gradle - jmh and jmhBaseline tasks. The JmhExecTask allows arbitrary command-line arguments to be passed to JMH benchmarks without validation. The 'jmhProfilers' task uses '-lprof' flag which lists available profilers, but there's no input validation or sanitization of user-supplied arguments that could be passed to these tasks. Fix: Implement input validation and argument whitelisting for JmhExecTask. Restrict profiler options to a predefined set and validate all user-supplied arguments.
  • Low · Missing License Header Configuration — codequality/spotless/licenseSlashstarStyle.txt. The spotless license configuration references 'licenseSlashstarStyle.txt' which should contain license headers, but the actual content validation is not visible. This could lead to inconsistent license header enforcement if misconfigured. Fix: Verify that license header configuration is properly enforced across all source files. Add pre-commit hooks to validate license headers are present.
  • Low · Benchmark Code Using Baseline Dependencies — benchmarks/build.gradle - compileOnly and baseline configurations. Benchmarks are compiled against older 'baseline' versions of reactor-core (libs.reactor.perfBaseline.core) which may contain known vulnerabilities. While this is intentional for performance comparison, it could inadvertently expose security issues if benchmarks are distributed. Fix: Ensure baseline dependencies are only used for benchmarking environments and never included in production distributions. Document why older versions are used. Consider using only stable, security-patched baseline versions.
  • Low · Missing Explicit Dependency Versions — benchmarks/build.gradle - dependencies block. The build.gradle uses imported library versions from 'libs' object without explicit version constraints visible in the provided snippet. Transitive dependencies could pull in vulnerable versions if not properly managed. Fix: Use a dependency lock file (gradle.lockfile) to ensure reproducible builds. Regularly scan dependencies with OWASP Dependency Check or similar tools. Explicitly declare vulnerable dependency exclusions if needed.

LLM-derived; treat as a starting point, not a security audit.


Generated by RepoPilot. Verdict based on maintenance signals — see the live page for receipts. Re-run on a new commit to refresh.

Healthy signals · reactor/reactor-core — RepoPilot