◉RORK LABJP
●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SDK 58 — Beta since 09/15 with no stable date yet; running projects in Expo Go has required login since 09/03●WIDGET — A write-up traces an iOS widget that renders black only in production builds●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…●GPT-6.1 SOL — Added to Rork's model menu (09-29) with Low, Medium and High effort; included on Pro and Max●SONNET 5.5 — Claude Sonnet 5.5 is selectable: strong at UI design and faster than Sonnet 5 (09-28)●SDK 58 — Beta since 09/15 with no stable date yet; running projects in Expo Go has required login since 09/03●WIDGET — A write-up traces an iOS widget that renders black only in production builds●OBSERVE — EAS Observe now records native crashes too (SDK 57.0.21 or later, 10/07)●NEW — My App Open Ad Only Showed When the App…
Articles/Dev Tools
⬡ Dev Tools/2026-04-25Advanced

Getting a 1GB Video Out of a Rork App Without Losing It — TUS, S3 Multipart, and Background Transfers

A production-ready implementation guide for uploading 1GB+ videos and high-resolution photos from Rork apps. Covers the TUS protocol, S3/R2 Multipart Upload, iOS background transfers, and a resumable progress UI — all with working code.

Rork585file uploadTUSS3 MultipartCloudflare R2background transfer

✦ Premium Article

"I'm uploading my video and the progress bar jumps back to zero the moment I step into an elevator." A user who hits that twice is done with your app.

I ran into this firsthand on a photo-sharing app I used to operate. A 200MB video that uploaded cleanly in testing had a 30–40% failure rate in production, specifically among users who "put their phone in a bag and boarded a train." The cause was simple: a naive fetch + FormData single-shot upload clashes head-on with the realities of mobile networks. This guide walks you through the implementation patterns that solve the problem from the root — with code you can ship.

Why "just fetch + FormData" breaks in production

If you design mobile file uploads the same way you'd design a browser upload, you'll walk straight into four walls.

① Network interruptions are the default, not the exception. Train gaps, underground malls, elevators, and handoffs between Wi-Fi and cellular all kill the TCP connection. A single-shot upload has to restart from zero every time. If you're 95% through a 1GB file when it drops, you just wasted 950MB.

② iOS will kill your background process without mercy. Even if the user doesn't force-quit the app, a standard URLSession stops sending after roughly 30 seconds in the background. Unless you reach for BGTaskScheduler or NSURLSession.background, the notion that your upload "keeps going in the background" is a fantasy.

③ Memory constraints are tight. readAsDataURL on a 1GB file will crash. In React Native / Expo, usable foreground memory sits somewhere between 800MB and 1.5GB depending on the device. Loading the full file into memory is an instant loss.

④ Servers have limits too. Most PaaS platforms cap request bodies: Cloudflare Workers at 100MB, Vercel Serverless at 4.5MB by default, Lambda behind API Gateway at 10MB. A single POST isn't going to clear those gates.

The design that addresses all four simultaneously is a resumable + chunked + background-capable upload foundation.

Three options to compare — which one to pick

There are three practical ways to do resumable, chunked transfers. Each has its sweet spot.

  • TUS protocol (tus.io): An open, HTTP-based standard. Client libraries exist in most languages, and the server side runs as either OSS (tusd) or Supabase Storage / Uppy Companion. Arbitrary chunk sizes, resume, and parallelism are all handled by the spec. The generalist choice.
  • S3 / R2 Multipart Upload: AWS's official protocol, supported by Cloudflare R2, MinIO, and other S3-compatible storage. Parts range from 5MB to 5GB, can be uploaded in parallel, and the combined object can be up to 5TB. The right call when you're writing directly to cloud storage.
  • Supabase Storage Resumable Upload: Supabase's storage layer speaks TUS under the hood, so you get resumable upload in a few lines from the JS client. The fastest path if you're already on Supabase.

My personal decision tree is straightforward: Cloudflare R2 as storage → Multipart Upload, Supabase backend → Supabase Storage Resumable, own API server handling files → TUS. When in doubt, work down that list.

✦

Thank you for reading this far.

Continue Reading

What follows includes implementation code, benchmarks, and practical content we hope you'll find useful. This site runs without ads — server and development costs are supported entirely by members like you. If it's been helpful, we'd be truly grateful for your support.

WHAT YOU'LL LEARN
✦You'll gain a resumable upload foundation that handles 1GB videos across network drops and app terminations — the failure mode that breaks user trust
✦You'll learn when to pick TUS vs S3 Multipart Upload vs Cloudflare R2, with production-ready client code for each path
✦You'll be able to ship background uploads with a progress UI that completes even when users leave the app
Secure payment via Stripe · Cancel anytime
✦

Unlock This Article

Get full access to the rest of this article. Buy once, read anytime. This site is ad-free — your support goes directly toward keeping it running.

or
Unlock all articles with Membership →
Share

Thank You for Reading

Rork Lab is ad-free, supported entirely by members like you. We publish practical guides daily with implementation code, benchmarks, and production-ready patterns. If you've found it useful, we'd love to have you on board.

  • ✦Copy-paste ready implementation code
  • ✦New advanced guides published daily
  • ✦$5/mo or $10 for lifetime access
View Membership →

Related Articles

⬡ Dev Tools2026-10-15
When EXPO_PUBLIC_ Values Read Fine in Dev but Come Back undefined in Production: Telling the Spellings Apart
The API URL reads fine while developing and turns undefined once the app is built. The cause was how process.env was written. I lined up babel-preset-expo's output for dev and production and tabulated which spellings get replaced and which are left behind.
⬡ Dev Tools2026-10-13
Before You Ship: Go Looking for Your Own Keys Inside the Exported Expo Bundle
A key can be missing from your source and still be sitting inside the finished app. I ran expo export on Expo SDK 57, searched the bundle with grep and a short Node script, and recorded which secrets show up and which don't.
⬡ Dev Tools2026-10-07
Japanese Headings Won't Turn Bold on Android: How to Trace and Fix a fontWeight That Does Nothing
A troubleshooting note for Rork apps where headings look bold on iPhone but stay thin on Android. How to tell the symptoms apart, pick weights through fontFamily, and verify the fix.