Skip to content

Uploads in depth

upload() from @vaifstudio/client/storage is the upload function to use for anything a user picks from disk. This page covers its options. For buckets, downloads and signed URLs see File Storage.

import { upload } from "@vaifstudio/client/storage";
const result = await upload(vaif, "videos", "lectures/week-1.mp4", file);
// result: { key: "lectures/week-1.mp4", sizeBytes: 104857600, multipart: true }
console.log(result);
File size What upload() does
Below multipartThreshold (default 5 MiB) One request
At or above it A multipart upload: parts of partSize (default 8 MiB), concurrency (default 3) at a time
await upload(vaif, "videos", "lectures/week-2.mp4", file, {
contentType: "video/mp4",
multipartThreshold: 16 * 1024 * 1024,
partSize: 16 * 1024 * 1024,
concurrency: 4,
});

Parts can’t be smaller than 5 MiB (except the last), so lower values for multipartThreshold and partSize are not useful.

onProgress fires after each completed part (once at the end for a one-request upload):

await upload(vaif, "videos", "lectures/week-3.mp4", file, {
onProgress: ({ loaded, total, fraction }) => {
console.log(`${loaded} of ${total} bytes (${Math.round(fraction * 100)}%)`);
},
});

Pass an AbortSignal. The upload rejects with a DOMException named AbortError:

const controller = new AbortController();
const cancelButton = document.querySelector("#cancel")!;
cancelButton.addEventListener("click", () => controller.abort());
try {
await upload(vaif, "videos", "lectures/week-4.mp4", file, { signal: controller.signal });
} catch (error) {
if (error instanceof DOMException && error.name === "AbortError") console.log("cancelled");
else throw error;
}

Give upload() a resume store. After every completed part it records which parts are done; calling upload() again for the same bucket and key picks up where it stopped instead of sending those parts again:

import { upload, localStorageResumeStore } from "@vaifstudio/client/storage";
const resume = localStorageResumeStore();
await upload(vaif, "videos", "lectures/week-5.mp4", file, { resume });
  • localStorageResumeStore() works in browsers. Entries are namespaced under vaif:upload: (change it with { prefix }).
  • An interrupted upload can be resumed for 24 hours. After that the server discards it and upload() starts again from the beginning.
  • If you cancel with a signal while a store is configured, the resume state is saved before the error is thrown, so the user can continue later.
  • Outside the browser, implement the ResumeStore interface (get, set, delete) over any storage you have.

@vaifstudio/client/storage/browser has uploadFromInput() and createDropZone(), which call upload() for each file the user picks or drops. See File storage.