React Native

How to Fix "React Native fetch Network Request Failed" on Local API

4 min read by DebuggedIt

Quick answer

Your React Native app's fetch call to a locally running API fails on a physical device or emulator, even though the exact same URL works perfectly when opened...

Your React Native app's fetch call to a locally running API fails on a physical device or emulator, even though the exact same URL works perfectly when opened in a browser on your development machine. This is almost always because "localhost" means something different from the device's perspective than it does on your computer.

The Problem

A straightforward fetch call throws a generic network error:

fetch('http://localhost:3000/api/users')
  .then(res => res.json())
  .catch(err => console.log(err));
[TypeError: Network request failed]

The same URL works fine when tested directly from your machine's terminal or browser:

$ curl http://localhost:3000/api/users
{"users": [...]}
"localhost" means a different device each time Your Mac localhost = itself, API here Phone / Emulator localhost = itself, no API here Fix: use your machine's LAN IP, or 10.0.2.2 on Android emulator

Why It Happens

"localhost" and 127.0.0.1 always refer to the device making the request, not your development machine specifically. When your API runs on your laptop and your React Native app runs on a separate physical device or a different virtual machine (an Android emulator), "localhost" from the app's perspective points at the phone or emulator itself, which has nothing listening on that port. This is a networking fact, not a React Native bug, but it trips up nearly everyone the first time they connect a mobile app to a local backend. Related, secondary causes once the address itself is correct:

  • iOS App Transport Security (ATS) blocking plain HTTP requests by default, since iOS strongly prefers HTTPS and requires explicit opt-in for HTTP during development.
  • Your development machine's firewall blocking incoming connections on the API's port from other devices on the network.
  • The physical device and your development machine are on different networks (device on cellular data, or connected to a different Wi-Fi network than your computer).

The Fix

For a physical device, use your development machine's actual local network IP address instead of localhost:

ipconfig getifaddr en0   # macOS
hostname -I               # Linux
fetch('http://192.168.1.42:3000/api/users')

Make sure your device and development machine are on the same Wi-Fi network — a phone on cellular data or a different network entirely has no route to your machine's local IP at all.

For an Android emulator specifically, use the special alias 10.0.2.2, which the Android emulator maps to your host machine's localhost automatically:

fetch('http://10.0.2.2:3000/api/users')

For an iOS simulator (not a physical device), localhost actually works correctly, since the iOS simulator shares your Mac's networking stack directly — if you're specifically using the simulator and still seeing this error, the cause is more likely ATS than the address itself.

For the iOS ATS issue, add a temporary exception during development in Info.plist to allow plain HTTP for your local API's address — this should never ship in a production build, only be used for local development:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSAllowsArbitraryLoads</key>
    <true/>
</dict>

A more targeted, safer alternative is exempting only your specific local development domain rather than allowing all arbitrary HTTP traffic:

<key>NSAppTransportSecurity</key>
<dict>
    <key>NSExceptionDomains</key>
    <dict>
        <key>192.168.1.42</key>
        <dict>
            <key>NSExceptionAllowsInsecureHTTPLoads</key>
            <true/>
        </dict>
    </dict>
</dict>

For a firewall blocking the connection, confirm your API server is actually bound to all network interfaces (not just 127.0.0.1) and that your machine's firewall allows inbound connections on the relevant port from your local network.

Still Not Working?

If you've addressed the address and ATS configuration but still see failures, verify connectivity independently of React Native entirely — try loading the API URL directly in the device's own mobile browser, which isolates whether this is a networking/reachability problem or something specific to your React Native fetch call or app code:

# On the physical device's browser
http://192.168.1.42:3000/api/users

If the browser on the device also can't reach it, the problem is purely network-level (firewall, wrong network, wrong IP) and has nothing to do with React Native at all — fix connectivity at that level first, then revisit the app code once a plain browser request succeeds from the same device.