Works with any backend npm install Zero dependencies

Custom strategy via MultipleUpload.registerStrategy()

Built-in strategies (single / chunked / s3 / azure / tus / urlImport) cover the common transports. For everything else - Google Cloud Storage resumable, a custom protocol against a legacy backend, WebRTC-style peer upload, or wrapping another SDK - register your own strategy. A strategy is just an object with an upload(task, uploader) method that returns a Promise.

Live demo. The uploader below uses a simulated strategy - no real server round-trip, just a fake progress emulator. Useful as a template for your own.
Strategy contract
MultipleUpload.registerStrategy('my-transport', {
 upload: function (task, uploader) {
 // Must honour task.abortController for cancel + pause.
 // Must call uploader._updateProgress(task, loaded, total) to advance UI.
 // Must resolve with an UploadResult-shaped object, or reject.

 return fetch('/my-endpoint', {
 method: 'POST',
 body: task.file,
 signal: task.abortController.signal
 }).then(r => r.json());
 },
 name: 'my-transport' // shown in task.metadata.strategy
});

// Use it:
new MultipleUpload('#uploader', { strategy: 'my-transport' });
Inline strategy objects

You can also pass a strategy object directly - no registry call needed. Great for one-off transports:

new MultipleUpload('#uploader', {
 strategy: {
 name: 'inline',
 upload: (task, uploader) => { /* ... */ }
 }
});
When to roll your own
  • Your backend expects a protocol MultipleUpload doesn't ship (GCS resumable, custom chunk headers, long-polling).
  • You need to inject auth-rotation, signed headers per request, or custom retry semantics.
  • You want to wrap an existing SDK (AWS SDK v3, GCS SDK, Cloudinary, ImageKit) with MultipleUpload's UI + progress model.
  • You need WebRTC / P2P / peer upload transport.
Full simulated example
MultipleUpload.registerStrategy('simulated', {
 upload: function (task, uploader) {
 return new Promise(function (resolve) {
 var total = task.file.size || 1024 * 1024;
 var loaded = 0;
 var tick = setInterval(function () {
 loaded = Math.min(loaded + total / 40, total);
 uploader._updateProgress(task, loaded, total);
 if (loaded >= total) {
 clearInterval(tick);
 resolve({ success: true, fileGuid: task.id,
 fileName: task.fileName, fileSize: total });
 }
 }, 60);
 });
 }
});

new MultipleUpload('#uploader', { strategy: 'simulated' });