npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

react-native-leak-detector

v1.1.0

Published

Static AST analysis tool for React Native memory leak patterns

Readme

react-native-leak-detector 🕵️‍♂️

npm version License: MIT

A zero-configuration, static AST analysis tool designed specifically for React and React Native projects. It detects common memory leak patterns that standard linters (like ESLint) often miss.

Why this exists

Memory leaks in React Native can silently crash your app with Out-of-Memory (OOM) exceptions. While ESLint react-hooks/exhaustive-deps ensures variables are synchronized, it doesn't verify if your timers, background subscriptions, and arrays are safely bounded and cleaned up.

react-native-leak-detector scans your source code using Babel AST traversal to identify high-risk logical leaks before they hit production. It is written in TypeScript and automatically respects your .gitignore rules!


🚀 Installation & Usage

You don't even need to install it! You can run it instantly using npx:

# Scan your entire source directory
npx react-native-leak-detector ./src

# Scan a single file
npx react-native-leak-detector ./src/components/MyComponent.tsx

# Output results as JSON (useful for custom scripts)
npx react-native-leak-detector ./src --format json

# Output results as a Markdown file (useful for GitHub Action PR comments)
npx react-native-leak-detector ./src --format markdown

Note: The detector automatically reads your .gitignore and .eslintignore files in the target directory and skips scanning those folders (like ios/, android/, and node_modules/).

Install as a Dev Dependency

If you want to add it to your CI/CD pipeline or package.json scripts:

npm install --save-dev react-native-leak-detector
# or
yarn add -D react-native-leak-detector

Then add a script to your package.json:

"scripts": {
  "lint:leaks": "react-native-leak-detector ./src"
}

You can then run the detector via:

npm run lint:leaks
# or
yarn lint:leaks

GitHub Actions Integration

We provide a drop-in template for GitHub Actions! Simply copy the contents of examples/github-action.yml into your project's .github/workflows/leak-detector.yml to automatically scan for memory leaks on every pull request.


🔍 What it Catches

1. Unbounded Array Growth (HIGH Severity)

Flags setState calls that spread arrays without capping their length. This is a massive cause of OOM crashes when hooked up to fast-firing intervals, frame processors, or location updates.

Bad:

// If called repeatedly in the background, memory will grow infinitely
setLocations(prev => [...prev, newLocation]);

Good:

// Safely caps the history at 100 items
setLocations(prev => [...prev, newLocation].slice(-100));

2. Missing Effect Cleanups (HIGH Severity)

Identifies useEffect hooks that instantiate timers, intervals, or event listeners, but fail to return a teardown function.

Bad:

useEffect(() => {
  const timer = setTimeout(() => doSomething(), 5000);
  // Leak: Timer keeps running if component unmounts early!
}, []);

3. Suspicious Effect Cleanups (MEDIUM Severity)

Identifies useEffect hooks that return a cleanup function, but the cleanup function doesn't appear to actually call a standard teardown method (clear, remove, stop, unsubscribe).

4. Unbalanced Timers (MEDIUM Severity)

Detects setTimeout or setInterval calls that aren't matched with a corresponding clearTimeout or clearInterval within the same file (unless returned to the caller).

5. Camera Lifecycles (HIGH Severity)

Ensures native camera sessions (like startRecording) are properly stopped in the same scope to prevent the native camera module from running invisibly in the background.

6. Animated Value Recreation (HIGH Severity)

Flags instances where new Animated.Value(0) or new Animated.ValueXY() are instantiated directly inside a functional component body. This causes a new animation object to be instantiated in memory on every render, leading to memory bloat and broken animations. Instead, they should be wrapped in useRef(...).current.

7. Missing Ref Cleanups (MEDIUM Severity)

Flags instances where a timer or subscription is assigned to a useRef (e.g., timerRef.current = setInterval(...)), but the file does not contain a corresponding cleanup call (e.g., clearInterval(timerRef.current)) in an unmount hook.

8. FlatList Inline Renders (MEDIUM Severity)

Flags instances where the renderItem prop of a FlatList or SectionList is defined as an inline anonymous function. In large lists, this creates a new function reference every render, destroying item memoization and spiking memory usage. It should be extracted via useCallback or moved outside the component.


⚙️ Configuration (Optional)

react-native-leak-detector is smart enough to work out-of-the-box. However, if you use custom hooks or custom cleanup methods, you can configure the detector by creating a detect-leaks.config.js file in your project root:

module.exports = {
  // Add custom hooks that behave like useEffect
  EFFECT_HOOKS: [
    'useEffect', 
    'useFocusEffect', 
    'useLayoutEffect', 
    'useMyCustomEffect'
  ],
  
  // Add custom cleanup function names that indicate teardown
  VALID_CLEANUP_KEYWORDS: [
    'clear', 
    'remove', 
    'stop', 
    'unsubscribe', 
    'dispose', 
    'cancel', 
    'teardown'
  ],
  
  // Custom subscription methods that require cleanup
  SUBSCRIBE_METHODS: [
    'addListener', 
    'addEventListener', 
    'on', 
    'subscribe',
    'watchPosition'
  ],
  
  // Custom timer methods
  TIMER_START: ['setInterval', 'setTimeout', 'requestAnimationFrame'],
  TIMER_CLEAR: ['clearInterval', 'clearTimeout', 'cancelAnimationFrame'],
};

🛑 Ignoring False Positives

If the detector flags a line that you know is safe, you can silence the warning by adding an inline comment immediately above the offending line:

// leak-detector-disable-next-line
AppState.addEventListener('change', mySafeHandler);

🤝 Contributing

Contributions, issues, and feature requests are welcome!

📝 License

This project is MIT licensed.