You will spend more time in the terminal than you think. Running the app is the easy part — cleaning caches, killing stuck Metro, reading logs, installing on a specific device, and shipping a release is where most of the day goes.
This is a practical cheat sheet: copy-paste scripts and commands for day-to-day React Native work on macOS (works for most Linux Android flows too).
Use it as a bookmark. Pin the sections you hit weekly.
Table of Contents
- Must-have
package.jsonscripts - Project bootstrap & install
- Metro bundler
- Run on Android
- Run on iOS
- Clean rebuild (when nothing works)
- adb — everyday Android
- iOS simulators, devices & pods
- Logs & debugging
- Release builds & bundles
- Useful one-liners & aliases
- Quick revision checklist
1. Must-have package.json scripts
Start with a solid script surface. Defaults from a new RN app are not enough for real projects.
{
"scripts": {
"start": "react-native start",
"start:reset": "react-native start --reset-cache",
"android": "react-native run-android",
"android:release": "react-native run-android --mode=release",
"ios": "react-native run-ios",
"ios:release": "react-native run-ios --configuration Release",
"lint": "eslint .",
"lint:fix": "eslint . --fix",
"test": "jest",
"test:watch": "jest --watch",
"typecheck": "tsc --noEmit",
"clean:android": "cd android && ./gradlew clean && cd ..",
"clean:ios": "cd ios && xcodebuild clean && cd ..",
"pods": "cd ios && pod install && cd ..",
"pods:update": "cd ios && pod install --repo-update && cd .."
}
}
Optional but high-value scripts many teams add:
{
"scripts": {
"android:device": "react-native run-android --deviceId=$(adb devices | awk 'NR==2{print $1}')",
"ios:sim": "react-native run-ios --simulator=\"iPhone 16\"",
"bundle:android": "react-native bundle --platform android --dev false --entry-file index.js --bundle-output android/app/src/main/assets/index.android.bundle --assets-dest android/app/src/main/res",
"bundle:ios": "react-native bundle --platform ios --dev false --entry-file index.js --bundle-output ios/main.jsbundle --assets-dest ios",
"doctor": "npx react-native doctor"
}
}
| Script | When you use it |
|---|---|
start:reset |
Weird module resolution, stale HMR, “Unable to resolve module” |
android:release / ios:release
|
Perf / ANR / animation checks that lie in Debug |
pods / pods:update
|
After RN upgrade or native dependency change |
doctor |
New machine, CI agent, “why won’t it build?” |
2. Project bootstrap & install
# Create app (RN CLI)
npx @react-native-community/cli@latest init MyApp
# Or with a specific version
npx @react-native-community/cli@latest init MyApp --version 0.86.0
# Install JS deps
yarn
# or
npm install
# iOS native deps
cd ios && bundle install && bundle exec pod install && cd ..
# if you don't use Bundler:
cd ios && pod install && cd ..
# Environment health check
npx react-native doctor
npx react-native info
Node / package manager tips
node -v
npm -v
yarn -v
watchman watch-del-all # if file watching is broken (macOS)
Pin Node with .nvmrc or engines in package.json so the whole team matches CI.
3. Metro bundler
# Start Metro
yarn start
# or
npx react-native start
# Start and wipe Metro cache
npx react-native start --reset-cache
# Custom port (when 8081 is taken)
npx react-native start --port 8082
# Then point the app at that port
adb reverse tcp:8082 tcp:8082
Kill a stuck Metro / free port 8081
# Find who owns 8081
lsof -i :8081
# Kill it
kill -9 $(lsof -t -i :8081)
# Nuclear option for node processes (use carefully)
killall node
Dev menu / reload (device or emulator)
| Action | Android | iOS Simulator |
|---|---|---|
| Dev menu | adb shell input keyevent 82 |
Cmd + D |
| Reload |
rr in Metro, or shake → Reload |
Cmd + R |
4. Run on Android
# Default emulator / device
yarn android
npx react-native run-android
# Specific variant / flavor
npx react-native run-android --mode=debug
npx react-native run-android --mode=release
npx react-native run-android --mode=stagingDebug # product flavors
# Specific device
adb devices
npx react-native run-android --deviceId=emulator-5554
npx react-native run-android --deviceId=<serial>
# Extra Gradle args
npx react-native run-android --active-arch-only # faster local debug builds
Gradle directly (when CLI is noisy)
cd android
./gradlew assembleDebug
./gradlew assembleRelease
./gradlew installDebug
./gradlew clean
./gradlew :app:dependencies > deps.txt
cd ..
List AVDs & start emulator
emulator -list-avds
emulator -avd Pixel_7_API_34 &
# Or via Android Studio → Device Manager
5. Run on iOS
# Default simulator
yarn ios
npx react-native run-ios
# Named simulator
npx react-native run-ios --simulator="iPhone 16"
npx react-native run-ios --simulator="iPhone 16 Pro Max"
# Physical device
npx react-native run-ios --device
# Release configuration
npx react-native run-ios --configuration Release
# Specific scheme / workspace (monorepos / custom Xcode setup)
npx react-native run-ios --scheme MyApp
Open Xcode when you need signing / native debugging
open ios/*.xcworkspace
# never open .xcodeproj if you use CocoaPods — use the workspace
6. Clean rebuild (when nothing works)
Memorize this ladder. Escalate only as far as you need.
Level 1 — JS / Metro
watchman watch-del-all
rm -rf $TMPDIR/metro-* $TMPDIR/haste-*
yarn start --reset-cache
Level 2 — Android
cd android && ./gradlew clean && cd ..
rm -rf android/app/build android/.gradle
yarn android
Level 3 — iOS
cd ios
rm -rf Pods Podfile.lock build
pod cache clean --all # optional, slower
pod install
cd ..
yarn ios
Level 4 — Full nuclear (local)
# JS
rm -rf node_modules
yarn cache clean
yarn
# Metro / temp
watchman watch-del-all
rm -rf $TMPDIR/metro-* $TMPDIR/haste-* $TMPDIR/react-*
# Android
cd android && ./gradlew clean && cd ..
rm -rf android/app/build android/.gradle
# iOS
cd ios
rm -rf Pods Podfile.lock build ~/Library/Developer/Xcode/DerivedData/*
pod install
cd ..
yarn start --reset-cache
Pro tip: Don’t jump to Level 4 every time. Most “white screen after upgrade” issues are Level 1 + Level 3.
7. adb — everyday Android
If you ship Android, adb is non-negotiable.
Devices & reverse ports
adb devices -l
adb kill-server && adb start-server
# Metro on physical device over USB
adb reverse tcp:8081 tcp:8081
# Multiple devices: pick one
adb -s emulator-5554 reverse tcp:8081 tcp:8081
Install / uninstall / clear data
# Replace with your applicationId from android/app/build.gradle
PACKAGE=com.myapp
adb install -r android/app/build/outputs/apk/debug/app-debug.apk
adb uninstall $PACKAGE
adb shell pm clear $PACKAGE # wipe app data
adb shell am force-stop $PACKAGE
Launch & deep links
PACKAGE=com.myapp
ACTIVITY=com.myapp.MainActivity
adb shell am start -n $PACKAGE/$ACTIVITY
# Deep link / intent
adb shell am start -a android.intent.action.VIEW -d "myapp://profile/123" $PACKAGE
Screenshots, recordings, input
adb shell screencap -p /sdcard/screen.png
adb pull /sdcard/screen.png .
adb shell screenrecord /sdcard/demo.mp4
# Ctrl+C to stop, then:
adb pull /sdcard/demo.mp4 .
adb shell input keyevent 82 # menu / RN dev menu
adb shell input text "hello"
Permissions & settings useful in QA
PACKAGE=com.myapp
adb shell pm grant $PACKAGE android.permission.CAMERA
adb shell pm revoke $PACKAGE android.permission.CAMERA
adb shell settings put global animator_duration_scale 0 # disable animations (CI)
adb shell settings put global animator_duration_scale 1
8. iOS simulators, devices & pods
Simulators
xcrun simctl list devices
xcrun simctl boot "iPhone 16"
open -a Simulator
# Install & launch a built app
xcrun simctl install booted path/to/MyApp.app
xcrun simctl launch booted com.myapp
# Wipe simulator
xcrun simctl erase all
# or one device:
xcrun simctl erase <UDID>
CocoaPods
cd ios
pod install
pod install --repo-update
pod update SomePodName
pod deintegrate && pod install # last-resort pods repair
cd ..
Derived Data (Xcode weirdness)
rm -rf ~/Library/Developer/Xcode/DerivedData/*
Physical device logs (quick)
xcrun devicectl device info list # Xcode 15+
# Or use Console.app filtered by your bundle id
9. Logs & debugging
React Native / Metro
# Metro already prints JS logs; for device logs use platform tools
npx react-native log-android
npx react-native log-ios
Android logcat (filter like a pro)
PACKAGE=com.myapp
adb logcat *:S ReactNative:V ReactNativeJS:V
adb logcat --pid=$(adb shell pidof -s $PACKAGE)
adb logcat | grep -iE "ReactNative|ReactNativeJS|AndroidRuntime|FATAL"
# Clear then capture a repro
adb logcat -c && adb logcat > rn-android.log
Flipper / DevTools (modern stacks vary)
# Chrome debugger is largely legacy; prefer:
# - React Native DevTools (newer RN)
# - React DevTools
# - Android Studio Profiler / Xcode Instruments for native
Hermes / bundle sanity
# Confirm Hermes is on (android/gradle.properties)
# hermesEnabled=true
# Inspect why a module is in the bundle (useful for size)
npx react-native-bundle-visualizer
10. Release builds & bundles
Android APK / AAB
cd android
# APK
./gradlew assembleRelease
# → android/app/build/outputs/apk/release/app-release.apk
# Play Store bundle
./gradlew bundleRelease
# → android/app/build/outputs/bundle/release/app-release.aab
cd ..
Signing must be configured in android/gradle.properties / keystore — never commit real secrets.
iOS archive (CLI sketch)
# Most teams archive from Xcode UI for signing.
# CLI shape for CI:
xcodebuild \
-workspace ios/MyApp.xcworkspace \
-scheme MyApp \
-configuration Release \
-destination 'generic/platform=iOS' \
-archivePath build/MyApp.xcarchive \
archive
Offline JS bundle (rare, but useful for native-only debugging)
npx react-native bundle \
--platform android \
--dev false \
--entry-file index.js \
--bundle-output android/app/src/main/assets/index.android.bundle \
--assets-dest android/app/src/main/res
npx react-native bundle \
--platform ios \
--dev false \
--entry-file index.js \
--bundle-output ios/main.jsbundle \
--assets-dest ios
Version bump reminders
| Place | What to bump |
|---|---|
android/app/build.gradle |
versionCode, versionName
|
ios/*/Info.plist or Xcode |
CFBundleShortVersionString, CFBundleVersion
|
package.json |
optional app metadata / CI |
11. Useful one-liners & aliases
Add to ~/.zshrc if you live in RN:
alias rn='npx react-native'
alias rns='npx react-native start'
alias rnsr='npx react-native start --reset-cache'
alias rna='npx react-native run-android'
alias rni='npx react-native run-ios'
alias adbr='adb reverse tcp:8081 tcp:8081'
alias adbd='adb devices -l'
alias metro-kill='kill -9 $(lsof -t -i :8081)'
alias rn-clean-metro='watchman watch-del-all; rm -rf $TMPDIR/metro-* $TMPDIR/haste-*'
Portable “fix my machine” script many teams keep as scripts/clean.sh:
#!/usr/bin/env bash
set -euo pipefail
watchman watch-del-all || true
rm -rf node_modules
yarn
rm -rf $TMPDIR/metro-* $TMPDIR/haste-* || true
(
cd android
./gradlew clean
rm -rf .gradle app/build
)
(
cd ios
rm -rf Pods Podfile.lock build
pod install
)
echo "Clean complete. Run: yarn start --reset-cache"
chmod +x scripts/clean.sh
./scripts/clean.sh
12. Quick revision checklist
Daily
- [ ]
yarn start/yarn android/yarn ios - [ ]
adb devices+adb reverse tcp:8081 tcp:8081for USB devices - [ ]
yarn start --reset-cachewhen modules look stale - [ ] Dev menu → Perf Monitor for jank checks
Weekly / after dependency changes
- [ ]
cd ios && pod install - [ ]
cd android && ./gradlew clean - [ ]
npx react-native doctor - [ ] Run a Release build before blaming “RN performance”
When stuck
- Kill Metro / free 8081
- Reset Metro cache + Watchman
- Gradle clean / Pods reinstall
- Wipe
DerivedData/node_modules -
npx react-native infoand compare with a teammate’s machine
Interview-ready one-liner
I keep a small set of scripts for start/reset, platform runs, pods/gradle clean, and
adb reverse— most RN “mysterious” bugs are cache, native deps, or Debug-vs-Release, not framework magic.
Bonus: commands you’ll look up forever
# Who is on 8081?
lsof -i :8081
# What’s my applicationId / bundle id again?
grep -R "applicationId" android/app/build.gradle
grep -R "PRODUCT_BUNDLE_IDENTIFIER" ios -n
# SHA-1 for Firebase / Google Sign-In (debug keystore)
keytool -list -v -keystore android/app/debug.keystore -alias androiddebugkey -storepass android -keypass android
# Clear macOS port / DNS weirdness after VPN (occasional)
sudo killall -HUP mDNSResponder
# Confirm JDK Android Studio expects
echo $JAVA_HOME
java -version
If you want a follow-up, the natural sequels are:
- CI scripts — GitHub Actions / Bitrise for RN lint, typecheck, Android AAB, iOS archive
-
Upgrade playbook —
react-native upgrade, align peers, Pods, Gradle -
Perf commands —
dumpsys gfxinfo, Instruments, Perf Monitor workflows (pair with a performance post)
Save this file, strip the frontmatter if you paste into DEV.to, add a cover image, and set published: true when you’re ready to ship.
Top comments (0)