If you’ve built a React Native or Expo app that talks to a backend running on your local machine, you’ve probably hit this problem:
localhost works on iOS simulator
10.0.2.2 works on Android emulator
nothing works on a real device
teammates use staging or remote APIs instead
And suddenly you’re debugging:
network routing
emulator networking
.env file switching
platform-specific base URLs
…instead of debugging your actual app.
This post explains why this happens, what’s really going on under the hood, and how I built a small tool to make development API URLs “just work” — safely.
👉 Tool: rn-dev-url
npm: npm install rn-dev-url
🔍 Why localhost behaves differently in React Native
React Native runs in different environments depending on where the app executes — and each one treats localhost differently.
Understanding this helps a lot.
🟣 iOS Simulator — shares your computer network
The iOS simulator runs on your host machine, so:
works fine — because both app + backend share the same network.
Everything feels intuitive here.
🟢 Android Emulator — runs in a virtualized network
The Android emulator runs inside a VM.
Inside that VM:
localhost refers to the emulator itself
not your computer
So Android exposes a special alias:
That IP maps back to your host machine.
It makes sense once you know it —
but it’s very unintuitive if you don’t.
🟡 Physical Devices — different network entirely
A real device is:
on your Wi-Fi network
not running inside your machine
not in a simulator
So the only way to reach your machine is via:
http://:
Which may fail if:
router isolation is enabled
firewall blocks access
VPN / hotspot affects routing
So behavior changes again.
Meanwhile… teammates may be using staging APIs
So environments look like this:
Context URL
iOS Simulator 127.0.0.1
Android Emulator 10.0.2.2
Device LAN IP
Another Dev Staging API
CI / Preview Remote API
Same codebase
6 different networking realities
And every context break means…
👉 switching .env files
👉 restarting the packager
👉 changing axios base URLs
👉 explaining networking to teammates
Small problem — high frequency — major friction.
🛠️ So I built a small tool to solve this: rn-dev-url
Instead of juggling device-specific URLs, I wanted:
predictable behavior
production-safe guardrails
no magic or heuristics
explicit fallbacks
zero native dependencies
So I built:
👉 rn-dev-url
A tiny utility that automatically resolves the correct API URL in React Native / Expo development — while never exposing LAN IPs or doing smart detection in production.
⚡ Install
npm install rn-dev-url
or
yarn add rn-dev-url
🔧 How it works
In development, it safely tries:
1️⃣ Android Emulator → 10.0.2.2:
2️⃣ iOS Simulator → 127.0.0.1:
3️⃣ LAN Device → 192.168.x.x: (optional)
Optionally verifies connectivity via:
/health
If nothing is reachable:
👉 it falls back to your remote dev / staging API
🛡 In production — detection is disabled by design
No LAN scanning
No auto-resolution
No environment guessing
✔ prodUrl is required
✔ only production URL is used
✔ zero surprises
This was a deliberate design choice.
🧩 Usage Example
import { getDevApiUrl } from "rn-dev-url";
const apiConfig = await getDevApiUrl(3000, {
prodUrl: "https://api.example.com",
healthPath: "/health",
});
console.log(apiConfig.url);
console.log(apiConfig.source);
Possible outputs:
http://10.0.2.2:3000 android-emulator
http://127.0.0.1:3000 ios-simulator
http://192.168.1.42:3000 lan-device
https://api.example.com prod (fallback)
Then use it with axios / fetch:
const api = axios.create({
baseURL: apiConfig.url,
});
No platform checks
No .env juggling
No emulator-only bugs
🎯 Who this is useful for
This tool helps if you:
✔ run backend locally during development
✔ test on emulator + simulator + device
✔ work in a team with mixed setups
✔ switch between local + staging APIs
✔ care about predictable behavior
It’s especially useful for:
Expo apps
mobile API development
developer onboarding
debugging device-only bugs
🧠 Why I avoided “clever auto-magic”
A lot of tools fail because they:
❌ guess environment behavior
❌ silently switch modes
❌ expose LAN IPs in prod
❌ behave differently per device
Instead, this tool is:
boring
explicit
safety-first
predictable
I’d rather be conservative & trustworthy than “smart”.
🚀 Try it out
npm install rn-dev-url
GitHub repo:
https://github.com/shahnoorgit/rn-dev-url
Medium write-up:
https://medium.com/@shahnoormujawar/i-built-a-tiny-tool-to-fix-one-of-the-most-annoying-react-native-dev-problems-cf411ae3de39
Top comments (0)