Queue uploads while offline; auto-resume when the connection returns
offlineMode: true turns MultipleUpload into an offline-first queue. Pick files with no network, hit upload - the queue is persisted to IndexedDB (state + Blob contents), all transfers pause, and a connectionChange event fires. When the network comes back, uploads automatically resume from where they were. Pair with a registered Service Worker for background-sync even when the tab is closed. None of Uppy, FilePond, Dropzone, or FineUploader offer this built-in.
Connection: Online
Try it:
- Open DevTools -> Network tab -> set to Offline.
- Pick a file. Hit upload. Note the queue is paused and the pill turns red.
- Reload the page. The file is still there - pulled from IndexedDB.
- Toggle Network back to Online. The upload resumes from byte 0 (or the last persisted chunk for chunked / S3 / GCS / tus).
Configuration
new MultipleUpload('#uploader', {
uploadUrl: '/api/upload',
offlineMode: true // forces persistState + indexeddb + persistBlobs
});What happens under the hood
- Forced defaults:
persistState: true,persistAdapter: 'indexeddb',persistBlobs: trueare applied automatically. Without them the queue can't survive a reload. - Online/offline events: listens to
window.addEventListener('online'/'offline')+ the initialnavigator.onLine. - Going offline: calls
pauseAll()internally. New tasks added while offline land inpausedstate. - Coming online: calls
resumeAll()+ kicks the queue. - Reload while offline: the IndexedDB-persisted state + Blobs rehydrate the queue. Uploads stay paused until
onlinefires.
Service Worker for background sync
Register a Service Worker to make uploads happen even with the tab closed:
// Once at app startup:
await MultipleUpload.registerServiceWorker('/upload-sw.js');
// Then enable offline mode on any uploader:
new MultipleUpload('#uploader', {
uploadUrl: '/api/upload',
offlineMode: true
});Reference Service Worker
// /upload-sw.js
self.addEventListener('sync', async (event) => {
if (event.tag === 'multipleupload-queue') {
event.waitUntil(replayQueuedUploads());
}
});
async function replayQueuedUploads() {
const db = await openMultipleUploadDB();
const queue = await db.getAll('pendingUploads');
for (const item of queue) {
try {
await fetch(item.url, {
method: 'POST', body: item.formData,
headers: item.headers
});
await db.delete('pendingUploads', item.id);
} catch (e) { /* will retry on next sync event */ }
}
}Use cases
- Field-data collection: capture photos / docs in remote areas, sync back to base.
- Flaky-network mobile: let users continue working in a tunnel / elevator.
- Bulk uploads with intermittent WiFi: the queue just resumes - no UI babysitting.
- Coffee-shop laptops: uploads survive captive-portal disconnects.