rxjs-leak-finder vs takeUntil / takeUntilDestroyed

takeUntil(destroy$) and Angular's takeUntilDestroyed() are the idiomatic way to auto-complete a stream when a component dies. They're excellent — and they only protect the streams you actually pipe them through. rxjs-leak-finder catches the ones you didn't.

The short version

takeUntil(this.destroy$) (classic) and takeUntilDestroyed() (Angular 16+, ties to the injection context) complete a stream when the component is destroyed, so its subscription ends. This is the recommended RxJS teardown pattern — declarative, composable, no manual unsubscribe().

It's still opt-in per stream. Miss the operator on one subscribe(), put it before another operator that re-subscribes, or subscribe in a place with no injection context, and that stream leaks silently. rxjs-leak-finder is the dev-time check that tells you when that happened — and points at the exact call site.

Feature comparison

Capabilityrxjs-leak-findertakeUntil / takeUntilDestroyed
Primary jobDetect leaked subscriptionsAuto-complete streams on destroy
Catches streams missing the operator✅ Yes❌ No — only protects piped streams
Operator-order mistakes (placed too early)✅ Surfaces resulting leak❌ Silently ineffective
BoilerplateOne line, app-widetakeUntil(destroy$) per stream (+ destroy subject) or takeUntilDestroyed() in injection context
Built into Angular❌ npm dev dependencytakeUntilDestroyed ships with Angular 16+
Production footprintNone (dev-only)Operator runs in prod (intended)

Use both — that's the intended workflow

takeUntilDestroyed() should be your default teardown. rxjs-leak-finder is how you confirm you applied it everywhere it's needed. Green dashboard = your operators are doing their job. Flagged subscription = one stream escaped, here's its stack trace.

// main.ts (dev only)
import { isDevMode } from '@angular/core';
import { enableRxjsLeakDetector } from 'rxjs-leak-finder';

if (isDevMode()) {
  enableRxjsLeakDetector();
}

FAQ

If I use takeUntilDestroyed everywhere, do I need rxjs-leak-finder?

"Everywhere" is the assumption that breaks. rxjs-leak-finder is how you check the assumption holds across the whole codebase — including code you didn't write. Cheap insurance for a silent, hard-to-debug bug class.

What's the difference between takeUntil and takeUntilDestroyed?

takeUntil(destroy$) needs you to create and next()/complete() a destroy subject in ngOnDestroy. takeUntilDestroyed() (Angular 16+) wires into the injection context's lifecycle automatically — less boilerplate, same idea. See how to unsubscribe in Angular.