Intro
A React Native local lab setup with practical examples helps you move from an observed problem to a verified result. The goal is operational safety: observe before changing, limit the blast radius, use placeholders instead of secrets, verify the result, and document how to recover if the expected state is not reached.
This guide is written for developers, DevOps consultants, and technical startup teams who need a reliable, repeatable local environment. It covers version and environment inventory, safe configuration paths, verification and diagnostics, failure modes and recovery, and a final operations checklist. Each section includes commands, expected output, failure signals, and recovery decisions for React Native setup, testing, examples, and development.
Before you begin, ensure your workstation meets these prerequisites:
- Node.js version 18 or higher (check with
node --version) - npm version 9 or higher (check with
npm --version) - Watchman installed and running (required on macOS and Linux for file watching)
- A code editor such as Visual Studio Code
- A device emulator (Android Studio's AVD or Apple Simulator) or a physical device with debugging enabled
Throughout this article, commands use placeholders like <app-name> or <device-id>. Replace them with your own values. Never put real credentials, tokens, private keys, or production identifiers in configuration files or commands.
Version and Environment Inventory
Before making any changes, identify the installed version, deployment topology, prerequisites, and the exact component you are inspecting. This section helps you capture the current state so that any later change is scoped and reversible.
Start by confirming the base toolchain versions. Open a terminal and run:
node --version
npm --version
npx react-native --version
Expected output on a healthy system looks like this:
v18.18.2
9.8.1
13.6.4
If any command fails or returns an older version, do not proceed with project configuration. First upgrade the missing component. For Node.js, use a version manager such as nvm:
nvm install 18
nvm use 18
For npm, run npm install -g npm@9 as an administrator or user with write access to the global npm directory.
Next, check whether the React Native CLI is installed globally or locally. The recommended approach is to use npx to run the CLI from your project's node_modules, which avoids version conflicts. Run npx react-native --version inside your project directory; it should return the version specified in the project's package.json.
If you plan to use Expo for prototyping, check the Expo CLI version separately:
npx expo --version
Expected output example: 6.3.10. Note that Expo and bare React Native have different command paths and configuration files. Keep them separate; do not mix workflows in the same project unless you are intentionally using Expo prebuild.
Record the versions in a lab-environment.txt file or a dedicated environment variable sheet. This makes it easier to compare against a clean machine or a teammate's setup.
Safe Configuration Path
Configuration changes are the most common source of broken local labs. The key principle: make one scoped change at a time, know its blast radius, and verify the result before moving on. Always keep a copy of the original configuration so you can revert quickly.
Initializing the Project
Create a new React Native project using the community CLI:
npx @react-native-community/cli init MyLabApp --version 0.73.4
This command creates a new directory MyLabApp with the specified React Native version. If you omit --version, the CLI installs the latest stable release, which may vary between machines. Pin the version in your project for consistency.
After initialization, navigate into the project and start the Metro bundler in a separate terminal:
cd MyLabApp
npx react-native start
Leave Metro running. In a second terminal, run the app on an emulator:
npx react-native run-android
Expected output includes lines such as:
BUILD SUCCESSFUL
Installing APK 'app-debug.apk' on 'Pixel_5_API_33(AVD)'
Starting: Intent { cmp=com.mylabapp/.MainActivity }
If you use iOS, run npx react-native run-ios --simulator="iPhone 15" and look for BUILD SUCCEEDED .
Editing Configuration Files
Suppose you need to change the application display name. In android/app/src/main/res/values/strings.xml, locate:
<string name="app_name">MyLabApp</string>
Change it to:
<string name="app_name">My Lab App</string>
Blast radius: affects only the Android app label, not the bundle ID, package name, or JavaScript code. Rebuild with npx react-native run-android and confirm the emulator shows the new name.
If the change does not appear, clear the build cache:
cd android
./gradlew clean
cd ..
npx react-native run-android
This is a heavier operation because it forces a full rebuild, so use it only when an incremental build fails.
For iOS, the display name lives in ios/MyLabApp/Info.plist under the key CFBundleDisplayName. Change the value and rerun npx react-native run-ios.
Always record the before and after values in your lab notes. That way, if the app behaves unexpectedly later, you can identify which configuration changed and when.
Verification and Diagnostics
Verification should be automatic and repeatable. Build a small set of checks that confirm the lab is working end-to-end: the bundler is running, the app installs, JavaScript runs, and native modules load.
Smoke Test Script
Create a scripts/verify-lab.sh file with the following content:
#!/usr/bin/env bash
set -euo pipefail
echo "Checking Node.js version >= 18"
node --version | grep -E '^v(1[8-9]|[2-9][0-9])\.' || { echo "Node.js too old"; exit 1; }
echo "Checking npm version >= 9"
npm --version | grep -E '^(9|1[0-9])\.' || { echo "npm too old"; exit 1; }
echo "Checking Metro bundler is responding"
curl -s http://localhost:8081/status | grep -q 'packager-status:running' || { echo "Metro not running"; exit 1; }
echo "All checks passed"
Make it executable and run it:
chmod +x scripts/verify-lab.sh
./scripts/verify-lab.sh
Expected output:
Checking Node.js version >= 18
Checking npm version >= 9
Checking Metro bundler is responding
All checks passed
If Metro is not running, the script exits with Metro not running. Start Metro with npx react-native start in a separate terminal and rerun the script.
Diagnosing Build Failures
When npx react-native run-android fails, first locate the error line in the Gradle output. Common patterns include:
SDK location not found-> openandroid/local.propertiesand ensuresdk.dirpoints to your Android SDK path, for example/Users/yourname/Library/Android/sdk.Could not resolve com.facebook.react:react-native:0.73.4-> check yourandroid/build.gradleandandroid/app/build.gradlefor the correct React Native version; sync the project or runcd android && ./gradlew --refresh-dependencies.Execution failed for task ':app:processDebugMainManifest'-> often caused by a malformed AndroidManifest.xml. Review the latest changes and run./gradlew processDebugMainManifest --stacktracefor details.
For iOS, run npx react-native run-ios --verbose to see detailed build steps. Common issues include missing CocoaPods dependencies (run cd ios && pod install) or code signing errors (temporarily set signing to automatic in Xcode, but never commit personal signing identities).
Diagnostic Checklist
Keep this checklist in your lab documentation and run it after every configuration change:
- [ ]
node --versionreturns v18 or later - [ ]
npm --versionreturns 9 or later - [ ]
npx react-native --versionmatches the project's package.json - [ ] Metro bundler responds on
http://localhost:8081/status - [ ] Emulator or device is recognized (
adb deviceson Android showsdevice,xcrun simctl list deviceson iOS shows a Booted device) - [ ]
npx react-native run-android(orrun-ios) completes without errors - [ ] App launches and renders the default screen
Failure Modes and Recovery
Even with a careful setup, local labs break. This section describes the most frequent failure modes, how to recognize them, and step-by-step recovery paths.
Failure Mode 1: Metro Bundler Port Conflict
Symptom: Starting Metro fails with Error: listen EADDRINUSE: address already in use :::8081.
Cause: Another process (perhaps an older Metro instance or a different tool) is already using port 8081.
Recovery: Find the process and kill it:
lsof -i :8081
# Note the PID, then:
kill -9 <PID>
Alternatively, start Metro on a different port:
npx react-native start --port 8082
Then run the app with npx react-native run-android --port 8082. Verify by opening http://localhost:8082/status in a browser.
Failure Mode 2: Android Emulator Not Found
Symptom: npx react-native run-android reports No connected devices or emulator not found.
Cause: The Android Emulator is not installed, the AVD is not created, or the ANDROID_HOME environment variable is missing.
Recovery:
- Check
ANDROID_HOME:
echo $ANDROID_HOME
If empty, add it to ~/.bashrc or ~/.zshrc:
export ANDROID_HOME=$HOME/Library/Android/sdk
export PATH=$PATH:$ANDROID_HOME/emulator:$ANDROID_HOME/tools:$ANDROID_HOME/platform-tools
- List available AVDs:
emulator -list-avds
If no AVD exists, create one using Android Studio's Device Manager or the command line:
avdmanager create avd -n Pixel_5_API_33 -k "system-images;android-33;google_apis;x86_64"
- Start the emulator and rerun the app.
Failure Mode 3: iOS Build Fails with CocoaPods could not find compatible versions
Symptom: pod install fails with a version conflict error.
Cause: The Podfile.lock is out of sync with the current Podfile, or a dependency requires a newer CocoaPods version.
Recovery:
- Update CocoaPods:
sudo gem install cocoapods - Delete
Podfile.lockandPodsfolder, then runpod install --repo-update. - If the conflict persists, check the specific pod version requirement in
Podfileand adjust it, or usepod update <PodName>to update only that pod.
Failure Mode 4: Fast Refresh Not Working
Symptom: Changes to JavaScript code do not appear in the app even after saving.
Cause: The Metro bundler lost the WebSocket connection to the app, or the app was built in release mode.
Recovery:
- Ensure the app is in debug mode (not release).
- Shake the device or press
Cmd+M(Android) /Cmd+D(iOS) in the emulator and select "Reload". - If Fast Refresh is disabled, enable it in the developer menu.
- Restart Metro and reinstall the app:
npx react-native run-android(orrun-ios).
Always document the recovery steps you used and their effectiveness. This builds a runbook for your team and reduces downtime in future incidents.
Common Pitfalls and How to Avoid Them
Pitfalls are mistakes that even experienced developers make because they seem harmless at first. Here are the most frequent ones in React Native local lab setups and how to steer around them.
Pitfall 1: Mixing Global and Local CLIs
Why it happens: Developers install react-native-cli globally for convenience, then run react-native commands from a project that expects a different version.
How to avoid: Always use npx react-native or the project's local binary in node_modules/.bin/react-native. Check with which react-native to see which binary is being used. If a global version exists, remove it: npm uninstall -g react-native-cli.
Pitfall 2: Hardcoding Absolute Paths in Configuration
Why it happens: Setting sdk.dir or other paths to a machine-specific absolute path, often copied from a teammate's setup.
How to avoid: Use environment variables and keep machine-specific values out of version control. For Android SDK, use local.properties (which is gitignored by default) and reference $ANDROID_HOME in build scripts. For other paths, use relative references or ~ expansion.
Pitfall 3: Running Commands from the Wrong Directory
Why it happens: Executing npx react-native run-android from a parent directory that does not contain the React Native project, leading to confusing errors.
How to avoid: Always confirm your working directory with pwd and ensure it contains package.json with React Native dependencies. Use terminal prompts or a script to check the directory before running commands.
Pitfall 4: Ignoring Emulator Architecture Mismatch
Why it happens: On Apple Silicon Macs, the Android emulator may require an ARM64 system image; installing an x86_64 image can cause slow performance or failure to start.
How to avoid: Check your machine's architecture (uname -m). If it is arm64, install ARM-compatible Android system images via the SDK Manager or sdkmanager "system-images;android-33;google_apis;arm64-v8a".
Pitfall 5: Committing Generated Native Files
Why it happens: New developers may commit the android/ and ios/ folders generated by the CLI, but over time these folders accumulate machine-specific caches and dependencies.
How to avoid: Use a .gitignore that excludes android/build, android/app/build, ios/Pods, and local.properties. If your team uses Expo prebuild, consider committing the generated native folders only after careful review, or use a CI step to generate them.
Operations Checklist
Use this checklist every time you start work in your lab, after any configuration change, and before running any test suite or demo. Each item includes an owner and review frequency for team environments.
| Check | Command or Signal | Expected Result | Owner | Review Frequency |
|---|---|---|---|---|
| Node.js version | node --version | v18.x or later | Priya Shah, Engineering Lead | Weekly |
| npm version | npm --version | 9.x or later | Priya Shah, Engineering Lead | Weekly |
| Project dependencies installed | npm ls --depth=0 | No UNMET DEPENDENCY or invalid | Marcus Chen, Frontend Developer | Before each coding session |
| Metro bundler status | curl -s http://localhost:8081/status | packager-status:running | Aisha Patel, QA Engineer | Before each test run |
| Emulator/device connected | adb devices (Android) / xcrun simctl list devices (iOS) | At least one device or Booted | Priya Shah, Engineering Lead | Before each deployment |
| App install and launch | npx react-native run-android / run-ios | Build successful and app starts | Marcus Chen, Frontend Developer | On every code change |
| Configuration changes logged | Lab notes file updated | No unrecorded changes | Aisha Patel, QA Engineer | Daily |
| Recovery runbook reviewed | Team review of failure modes | Updated with latest incidents | Priya Shah, Engineering Lead | Monthly |
The owner is a single accountable person, not a group. If the check fails, the owner decides whether to fix immediately or escalate. Review frequencies ensure that the lab stays healthy even as team members change.
Conclusion
A React Native local lab setup with practical examples is useful only when each recommendation is version-scoped, observable, and reversible where the technology permits. Copying a command without checking prerequisites and expected output is not an operations procedure.
Start with one low-risk verification: run npx react-native --version and compare it to your project's package.json. Record the current state, then run the verification script from this guide. If any check fails, use the failure modes and recovery section to address it before making further changes. Review dependencies such as Expo, Android, and REST API integrations only after the base lab is stable.
A reliable technical workflow makes failure visible, protects sensitive values, limits changes to the intended resource, and defines recovery verification before an incident forces the decision. Build your lab with these principles, and you will spend less time debugging and more time shipping.