Fetching latest headlines…
I built a native React Native downloader because AI models are huge
NORTH AMERICA
🇺🇸 United StatesJuly 1, 2026

I built a native React Native downloader because AI models are huge

0 views0 likes0 comments
Originally published byDev.to

I ran into this while building Orb, a private offline AI app for Android.

Orb runs local models on the phone. That is great for privacy, but it creates a very practical mobile problem: the app has to download model files that can be multiple gigabytes. If the network drops, the app backgrounds, or the user force-closes the app, restarting from zero is a terrible experience.

So I pulled the downloader out into a small open-source package:

GitHub: https://github.com/zraisan/react-native-client

NPM: https://www.npmjs.com/package/react-native-client

react-native-client is a native HTTP client for React Native apps that need direct-to-file downloads without moving bytes through the JavaScript bridge. The first stable API is focused on downloads, not general HTTP requests.

What it does

The package exposes a typed downloadFile API through Nitro Modules.

Under the hood:

  • Android uses OkHttp
  • iOS uses URLSession
  • files are streamed directly to disk on the native side
  • progress callbacks report bytes written and total length
  • resumable downloads use HTTP Range requests
  • partial-file resume validates Content-Range before appending
  • Android background mode uses a foreground service
  • iOS uses a background URLSession path

The main use case is large files: AI models, media packs, offline datasets, cache warmups, and anything else where a failed 2GB download should not mean starting over.

Basic usage

import { downloadFile, documentDirectoryPath } from 'react-native-client'

const result = await downloadFile({
  fromUrl: 'https://example.com/model.gguf',
  toFile: `${documentDirectoryPath}/model.gguf`,
})

console.log(result.statusCode, result.bytesWritten)

With progress:

await downloadFile({
  fromUrl: 'https://example.com/large-file.bin',
  toFile: `${documentDirectoryPath}/large-file.bin`,
  begin: (statusCode, contentLength) => {
    console.log('started', statusCode, contentLength)
  },
  onProgress: (bytesWritten, contentLength) => {
    if (contentLength > 0) {
      console.log(`${Math.round((bytesWritten / contentLength) * 100)}%`)
    }
  },
})

Resumable background download:

await downloadFile({
  fromUrl: 'https://example.com/model.gguf',
  toFile: `${documentDirectoryPath}/model.gguf`,
  resumable: true,
  background: true,
  connectionTimeout: 30000,
  readTimeout: 30000,
  onProgress: (bytesWritten, contentLength) => {
    console.log(bytesWritten, contentLength)
  },
})

To resume after app relaunch, call the same request again with the same toFile and resumable: true. If the partial file is still there, the native client requests only the missing range.

const modelPath = `${documentDirectoryPath}/model.gguf`

await downloadFile({
  fromUrl: modelUrl,
  toFile: modelPath,
  resumable: true,
  background: true,
})

Why not just fetch?

For small files, normal app-level download logic is fine.

For Orb, the files are not small. A local AI model download needs to survive boring real-world mobile behavior: bad Wi-Fi, app backgrounding, retries, foreground service expectations on Android, and users reopening the app later.

I wanted the heavy transfer to stay native:

  • no file bytes crossing the JS bridge
  • native networking behavior on each platform
  • progress events for the UI
  • partial-file recovery when the server supports Range
  • safe restart when resume metadata is wrong or unsupported

The package is not trying to be a full download manager yet. It does not currently expose task IDs, cancellation, a persistent queue, checksums, uploads, or a general request/response client. The current goal is narrower: make large direct-to-file downloads reliable enough to build real product flows around them.

Install

npm install react-native-client react-native-nitro-modules
yarn add react-native-client react-native-nitro-modules
bun add react-native-client react-native-nitro-modules

For iOS:

cd ios
pod install

Android should work through normal React Native autolinking.

Current status

The package is early, but usable for the download flow it was built for.

Current version: 0.0.3

Requirements:

  • React Native app
  • react-native-nitro-modules >=0.35.0 <0.36.0
  • Android and/or iOS native builds

The README has a demo showing Android resume behavior: start a native background download, send the app home, return to the transfer, force-stop the app, relaunch, and resume from the partial file.

Why I’m releasing it

Orb needed this because private offline AI has a surprisingly unglamorous bottleneck: getting the model onto the device cleanly. The AI part gets the attention, but the first user experience is often just a large download that must not fail in a stupid way.

If you are building a React Native app that downloads big files, I’d love feedback on the API before it grows too much.

The next useful pieces are probably:

  • task IDs and cancellation
  • persistent background task registry
  • request headers and response metadata
  • checksum verification
  • upload support
  • broader HTTP APIs beyond file download

GitHub: https://github.com/zraisan/react-native-client

NPM: https://www.npmjs.com/package/react-native-client

Orb on Google Play: https://play.google.com/store/apps/details?id=com.falaq.orb

Comments (0)

Sign in to join the discussion

Be the first to comment!