Uploading Images from React Native to a Node.js API

TIL that a multipart upload from React Native needs the file described as an object with uri/name/type, not sent as a raw file:// string — an easy mismatch to miss since it fails silently on some devices.

2 min read

Sabin Shrestha

Full-Stack Developer — Next.js, React & React Native

The Problem #

Sending a photo from the driver app to the delivery API meant building a multipart request, and the first version just appended the file:// URI string to FormData the way you might append any other field.

Context #

This was the photo-proof-of-delivery upload — a driver takes a photo, it needs to reach the Node.js API and get attached to the delivery record.

What I Tried #

const formData = new FormData();
formData.append("photo", photoUri); // wrong: just a string

What Went Wrong #

The request reached the server, but multer on the receiving end saw a text field, not a file — no binary content, no filename, no content type. The upload "succeeded" from the client's point of view (no thrown error) while producing nothing usable server-side, which made it look like a backend bug at first.

The Solution #

React Native's FormData expects a file field to be an object describing the URI, filename, and MIME type — not the URI on its own.

const formData = new FormData();
formData.append("photo", {
  uri: photoUri,
  name: "delivery-proof.jpg",
  type: "image/jpeg",
} as any); // React Native's FormData typing doesn't match the DOM's
 
await fetch(`${API_URL}/deliveries/${id}/photo`, {
  method: "POST",
  body: formData,
  headers: { "Content-Type": "multipart/form-data" },
});

Why It Works #

React Native's FormData implementation is a shim over the native networking layer, not a literal browser FormData — it needs that shape (uri/name/type) to know how to stream the actual file bytes from the device's filesystem into the multipart body. A plain string has no filename or content type for it to work with.

Lessons Learned #

The failure mode here — no client-side error, no server-side crash, just a missing file — is exactly the kind of bug that survives in production because nothing obviously breaks. It only surfaces when someone notices a delivery record with no photo attached.

What I Would Do Differently #

I'd add a server-side check that rejects (with a clear error) any multipart field it can't identify as an actual uploaded file, so a malformed client request fails loudly instead of silently dropping the photo.

multipart/form-data, multer file parsing, React Native's FormData vs. the browser's.