
Product
Introducing Repository Access Permissions and Custom Roles
Socket now supports Custom Roles and Repository Access Permissions so organizations can control who can access specific repositories and actions.
react-native-nitro-fetch
Advanced tools
react-native-nitro-fetch is a general purpose network fetching library for React Native. It can be used as a drop-in replacement for the built-in fetch(...) method, as well as provide additional features like prefetching and workletized mappers.
fetch(...) methodreact-native-nitro-websockets (see WebSockets & prewarm below)npm i react-native-nitro-fetch react-native-nitro-modules
Nitro Modules requires react-native 0.75+ or higher
WebSockets (optional) — add the companion socket package plus text decoder (peer dependency of websockets):
npm i react-native-nitro-websockets react-native-nitro-text-decoder
Full setup, native hooks, prewarm, and API details: docs/websockets.md · UI: example/src/screens/WebSocketScreen.tsx · auth + prewarm: Token refresh (example block).
To simply fetch data, import the fetch(...) method from react-native-nitro-fetch:
import { fetch } from 'react-native-nitro-fetch'
const res = await fetch('https://httpbin.org/get')
const json = await res.json()
This can be used as a drop-in-replacement for the built-in fetch(...) method.
You can prefetch a URL in JS, which keeps the result cached for the next actual fetch(...) call - this can be used shortly before navigating to a new screen to have results hot & ready:
import { prefetch } from 'react-native-nitro-fetch'
await prefetch('https://httpbin.org/uuid', {
headers: { prefetchKey: 'uuid' }
})
Then, on the new screen that was navigated to:
import { fetch } from 'react-native-nitro-fetch'
const res = await fetch('https://httpbin.org/uuid', {
headers: { prefetchKey: 'uuid' }
})
console.log('prefetched header:', res.headers.get('nitroPrefetched'))
Prefetching data on app launch (or process start) will make it hot & ready once your JS code actually runs. Call prefetchOnAppStart(...) to enqueue a prefetch for the next app start:
import { prefetchOnAppStart } from 'react-native-nitro-fetch'
await prefetchOnAppStart('https://httpbin.org/uuid', {
prefetchKey: 'uuid'
})
Then, once the app opens the next time, a call to fetch(...) might resolve faster since it will contain already cached results:
import { fetch } from 'react-native-nitro-fetch'
const res = await fetch('https://httpbin.org/uuid', {
headers: { prefetchKey: 'uuid' }
})
console.log('prefetched header:', res.headers.get('nitroPrefetched'))
In our tests, prefetching alone yielded a ~220 ms faster TTI (time-to-interactive) time! 🤯
When you use auto-prefetch (prefetchOnAppStart) and/or WebSocket prewarm on app start (react-native-nitro-websockets), native code runs before your JS bundle. If those requests need auth headers, you can register a token refresh configuration. On each cold start, native code calls your refresh URL, maps the response into HTTP headers, and merges them into auto-prefetches and/or WebSocket prewarms.
1. Register the refresh config (persisted in encrypted native storage):
import { registerTokenRefresh } from 'react-native-nitro-fetch'
registerTokenRefresh({
target: 'fetch', // 'websocket' | 'fetch' | 'all'
url: 'https://api.example.com/oauth/token',
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ grant_type: 'client_credentials' }),
responseType: 'json',
mappings: [
{ jsonPath: 'access_token', header: 'Authorization', valueTemplate: 'Bearer {{value}}' },
],
// If the refresh request fails:
// - 'useStoredHeaders' — use last successful headers from the previous run (default)
// - 'skip' — skip auto-prefetch / prewarm entirely when refresh fails
onFailure: 'useStoredHeaders',
})
Response mapping
responseType is 'json'. Use mappings to copy fields from the JSON body into header names (dot paths supported, e.g. data.token).compositeHeaders to build a header from a template and multiple JSON paths ({{placeholder}} in the template).responseType: 'text' and use textHeader / optional textTemplate (with {{value}}).fetch path only), use bodyMappings / formDataMappings (see below).Example: header + JSON body + form-data mappings
One config can fan the same refreshed value into all three destinations. Each mapping only applies to a prefetch whose body it matches — bodyMappings won't synthesize a JSON body on a GET/form request, and formDataMappings won't make a request multipart.
import { registerTokenRefresh } from 'react-native-nitro-fetch'
// Refresh endpoint returns e.g. { "data": { "accessToken": "abc123" } }
registerTokenRefresh({
target: 'fetch',
url: 'https://api.example.com/oauth/token',
method: 'POST',
responseType: 'json',
// 1) header mapping → sets a request header
mappings: [
{ jsonPath: 'data.accessToken', header: 'Authorization', valueTemplate: 'Bearer {{value}}' },
],
// 2) JSON-body mapping → sets a (nested) dot-path key in the prefetch's JSON body
bodyMappings: [
{ jsonPath: 'data.accessToken', bodyPath: 'auth.token' },
],
// 3) form-data mapping → replaces/appends a multipart field by name
formDataMappings: [
{ jsonPath: 'data.accessToken', field: 'token' },
],
onFailure: 'useStoredHeaders',
})
Result, per prefetch:
{ "deviceId": "d-1" } → Authorization: Bearer abc123 and body { "deviceId": "d-1", "auth": { "token": "abc123" } }Authorization: Bearer abc123 and a token=abc123 partFor
responseType: 'text', the body/form equivalents oftextHeaderarebodyTextPath/formDataTextField.
Example: token refresh + WebSocket prewarm
import { registerTokenRefresh } from 'react-native-nitro-fetch'
import { prewarmOnAppStart, NitroWebSocket } from 'react-native-nitro-websockets'
const WSS = 'wss://api.example.com/live'
registerTokenRefresh({
target: 'websocket', // use 'all' if you also use prefetchOnAppStart with the same token flow
url: 'https://api.example.com/oauth/token',
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
grant_type: 'client_credentials',
client_id: '…',
client_secret: '…',
}),
mappings: [
{ jsonPath: 'access_token', header: 'Authorization', valueTemplate: 'Bearer {{value}}' },
],
})
3. Optional JS helpers
import {
callRefreshEndpoint,
clearTokenRefresh,
getStoredTokenRefreshConfig,
} from 'react-native-nitro-fetch'
// Same mapping rules as native; uses global fetch from JS
const headers = await callRefreshEndpoint(config)
// Remove stored config and token caches (scope with 'fetch' | 'websocket' | 'all')
clearTokenRefresh('fetch')
// Read back what was registered (or null)
const stored = getStoredTokenRefreshConfig('fetch')
The refresh config and header caches are stored with platform secure storage (Android Keystore + encrypted values in SharedPreferences, iOS Keychain-backed encryption in the same UserDefaults suite as other nitro keys).
Cancel in-flight requests using the standard AbortController API:
import { fetch } from 'react-native-nitro-fetch'
const controller = new AbortController()
// Abort after 500ms
setTimeout(() => controller.abort(), 500)
try {
const res = await fetch('https://httpbin.org/delay/20', {
signal: controller.signal,
})
} catch (e) {
if (e.name === 'AbortError') {
console.log('Request was cancelled')
}
}
Pre-aborted signals are also supported — the request will throw immediately without making a network call:
const controller = new AbortController()
controller.abort()
await fetch(url, { signal: controller.signal }) // throws AbortError
Upload files and form fields using FormData:
import { fetch } from 'react-native-nitro-fetch'
const fd = new FormData()
fd.append('username', 'nitro_user')
fd.append('avatar', {
uri: 'file:///path/to/photo.jpg',
type: 'image/jpeg',
name: 'avatar.jpg',
} as any)
const res = await fetch('https://httpbin.org/post', {
method: 'POST',
body: fd,
})
const json = await res.json()
Since Nitro Fetch is a Nitro Module, it can be used from Worklets. This can be useful to parse data without blocking the main JS-Thread:
import { nitroFetchOnWorklet } from 'react-native-nitro-fetch'
const data = await nitroFetchOnWorklet(
'https://httpbin.org/get',
undefined,
(payload) => {
'worklet'
return JSON.parse(payload.bodyString ?? '{}')
}
)
Before using worklet mapping, install and configure react-native-worklets.
TextDecoderNitro Fetch can also expose an streaming mode that returns a ReadableStream body.
Combined with react-native-nitro-text-decoder, you can incrementally decode UTF‑8 chunks:
import { useRef, useState } from 'react'
import { fetch as nitroFetch } from 'react-native-nitro-fetch'
import { TextDecoder } from 'react-native-nitro-text-decoder'
export function StreamingExample() {
const [output, setOutput] = useState('')
const decoder = useRef(new TextDecoder())
const append = (text: string) => {
setOutput(prev => prev + text)
}
const runStream = async () => {
// `stream: true` enables the streaming transport
const res = await nitroFetch('https://httpbin.org/stream/20', {
stream: true,
})
const reader = res.body?.getReader()
if (!reader) {
append('No readable stream!')
return
}
let chunks = 0
while (true) {
const { done, value } = await reader.read()
if (done) break
chunks++
const text = decoder.current.decode(value, { stream: true })
append(text)
}
append(`\n\n✅ Done — ${chunks} chunk(s) received`)
}
// Call `runStream()` from a button handler in your UI
}
Use react-native-nitro-websockets for NitroWebSocket (browser-like API: onopen, onmessage, send, close, …). Install react-native-nitro-text-decoder alongside it — the socket package uses it to decode UTF-8 text frames.
Prewarm on next launch — queue URLs from JS so native code can start the handshake before React loads:
import {
prewarmOnAppStart,
removeFromPrewarmQueue,
clearPrewarmQueue,
} from 'react-native-nitro-websockets'
prewarmOnAppStart('wss://echo.websocket.org')
// optional: prewarmOnAppStart(url, ['subproto'], { Authorization: 'Bearer …' })
clearPrewarmQueue()
removeFromPrewarmQueue('wss://echo.websocket.org')
On Android, call NitroWebSocketAutoPrewarmer.prewarmOnStart(this) in Application.onCreate (see example MainApplication.kt). iOS picks up the queue via the linked pod.
Authenticated prewarms: use registerTokenRefresh with target: 'websocket' or 'all' — see Token refresh (cold start) for a small registerTokenRefresh + prewarmOnAppStart + NitroWebSocket example.
More detail: docs/websockets.md · UI sample: example/src/screens/WebSocketScreen.tsx.
react-native-nitro-fetch itself; use the companion package react-native-nitro-websockets (with react-native-nitro-text-decoder). For other stacks, react-native-fast-io is another option.Nitro Fetch is built with ❤️ by Margelo. We build fast and beautiful apps. Contact us at margelo.com for high-end consultancy services.
CONTRIBUTING.md#development-workflowCONTRIBUTING.md#sending-a-pull-requestCODE_OF_CONDUCT.mdMIT
FAQs
Awesome Fetch :)
The npm package react-native-nitro-fetch receives a total of 19,106 weekly downloads. As such, react-native-nitro-fetch popularity was classified as popular.
We found that react-native-nitro-fetch demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 2 open source maintainers collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Product
Socket now supports Custom Roles and Repository Access Permissions so organizations can control who can access specific repositories and actions.

Product
Socket MCP now lets AI assistants review org alerts, investigate threats using the Socket threat feed, and inspect package files in addition to dependency scoring.

Product
Socket Firewall blocks malicious VS Code and Open VSX extensions before install, protecting developers from compromised editor marketplaces.