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

@salve-software/react-native-hotswap

v0.2.0

Published

Hot-swap the native side of a running React Native app: Kotlin and C++ on Android, Swift and C++ on the iOS simulator. Safest with Nitro.

Readme

react-native-hotswap

@salve-software/react-native-hotswap

Fast Refresh covers your JavaScript. This covers the other half: the Kotlin, Swift and C++ underneath it.

hotswap  watching android/src/main/java  →  127.0.0.1:8099
  ✅ probe/android/src/main/java/com/probe/ProbeValues.kt  1234ms
  ✅ probe/cpp/probe.cpp  435ms

| | Save to running | | --------------------- | ----------------------------------------- | | Rebuild and reinstall | 10–30s, and the app restarts from scratch | | hotswap, Kotlin | ~1s, same process | | hotswap, C++ | ~0.5s Android, ~3s iOS | | hotswap, Swift | ~6s, same process |

Install

npm install --save-dev @salve-software/react-native-hotswap

Two lines in metro.config.js, and Android is done:

const { withHotswap } = require('@salve-software/react-native-hotswap/metro.cjs');

// `roots` is optional. Pass one per place you keep native code.
module.exports = withHotswap(mergeConfig(getDefaultConfig(__dirname), config));

The watcher starts with Metro and the agent attaches when the app launches. Everything else is read out of your Gradle build. There is nothing to add to build.gradle and nothing to call from your code.

On Expo, add "@salve-software/react-native-hotswap" to plugins in app.json instead of editing native files by hand, and use a development build. docs/expo.md covers it.

Swift needs two more lines in the Podfile. Without them a Swift method cannot be replaced at all:

require Pod::Executable.execute_command('node', ['-p',
  'require.resolve("@salve-software/react-native-hotswap/hotswap.rb", {paths: [process.argv[1]]})',
  __dir__]).strip

# inside post_install
hotswap_post_install(installer)

New files and removed methods

Patching rewrites code that is already loaded, so it cannot add a class or remove a method. When the runtime refuses for that reason, hotswap publishes a generation instead: it rebuilds the module, loads it beside what is running, and React Native builds its next instance from it.

  ♻️  probe/android/.../BornAtRuntime.kt  reloaded from a new generation  942ms

The cost is your JS state. React rebuilds its instance, so the app goes back to its first screen. The process keeps running, and patching is still tried first.

Generations need one line per platform:

// MainApplication.kt
override val reactHost: ReactHost by lazy {
  HotswapReactHost.create(applicationContext) { PackageList(this).packages }
}
// your RCTDefaultReactNativeFactoryDelegate subclass
import RNHotswap

@objc(getModuleClassFromName:)
func hotswapModuleClass(_ name: UnsafePointer<CChar>) -> AnyClass? {
  Hotswap.moduleClass(fromName: name)
}

Leave them out and patching still works. Only generations stop.

What you see

A successful swap draws a violet pill over the running app. It is not React Native's blue bar on purpose, so you can tell which half of the app changed when both show up. A failed swap draws nothing, and the terminal says why.

When a save seems to do nothing, run npx hotswap --check. It lists what is wired up and what is not. Usually the app is not running, or the build was not debuggable.

Limits

| Change | Result | | -------------------------------------- | ----------------------------------------- | | Method body, anywhere | ✅ patched | | New method or field on a class | ✅ patched, Android 11+ | | A class in a new file | ✅ a generation | | Removing a method or field | ✅ a generation | | MainActivity, MainApplication | patched only. A reload keeps the Activity | | Objective-C, inlined code, iOS devices | ⛔ never | | Release builds | ⛔ by design |

| Requires | | | -------- | ------------------------------------------------------------------------------------- | | Android | API 28 to attach, API 30 for structural changes | | iOS | simulator only | | Build | debuggable, build tools 34–36 (not 37) |

Docs

example/ is a React Native app with its own native code and a module beside it, both wired up. Run cd example && npm install && npx react-native start, then edit one of the files it lists on screen.

| Doc | What is in it | | ------------------------------------ | -------------------------------------------------- | | Expo | the config plugin, and why a dev build is required | | How it works | JVMTI, dynamic replacement, vtables, and prior art | | Generations | the second mechanism, in full | | Limits | everything that does and does not swap |

Licence

MIT.

android/src/main/cpp/vendor/jvmti.h comes from AOSP and is GPLv2 with the Classpath Exception, so linking against it imposes nothing on this package. The header is kept as published, with its licence notice intact.