Storage

Resumable Uploads

Learn how to upload files to Supabase Storage.

The resumable upload method is recommended when:

  • Uploading large files that may exceed 6MB in size
  • Network stability is a concern
  • You want to have progress events for your uploads

Supabase Storage implements the TUS protocol to enable resumable uploads. TUS stands for The Upload Server and is an open protocol for supporting resumable uploads. The protocol allows the upload process to be resumed from where it left off in case of interruptions. This method can be implemented using the tus-js-client library, or other client-side libraries like Uppy-js that support the TUS protocol.

Here's an example of how to upload a file using tus-js-client:


_51
const tus = require('tus-js-client')
_51
_51
const projectId = ''
_51
_51
async function uploadFile(bucketName, fileName, file) {
_51
const { data: { session } } = await supabase.auth.getSession()
_51
_51
return new Promise((resolve, reject) => {
_51
var upload = new tus.Upload(file, {
_51
endpoint: `https://${projectId}.supabase.co/storage/v1/upload/resumable`,
_51
retryDelays: [0, 3000, 5000, 10000, 20000],
_51
headers: {
_51
authorization: `Bearer ${session.access_token}`,
_51
'x-upsert': 'true', // optionally set upsert to true to overwrite existing files
_51
},
_51
uploadDataDuringCreation: true,
_51
removeFingerprintOnSuccess: true, // Important if you want to allow re-uploading the same file https://github.com/tus/tus-js-client/blob/main/docs/api.md#removefingerprintonsuccess
_51
metadata: {
_51
bucketName: bucketName,
_51
objectName: fileName,
_51
contentType: 'image/png',
_51
cacheControl: 3600,
_51
},
_51
chunkSize: 6 * 1024 * 1024, // NOTE: it must be set to 6MB (for now) do not change it
_51
onError: function (error) {
_51
console.log('Failed because: ' + error)
_51
reject(error)
_51
},
_51
onProgress: function (bytesUploaded, bytesTotal) {
_51
var percentage = ((bytesUploaded / bytesTotal) * 100).toFixed(2)
_51
console.log(bytesUploaded, bytesTotal, percentage + '%')
_51
},
_51
onSuccess: function () {
_51
console.log('Download %s from %s', upload.file.name, upload.url)
_51
resolve()
_51
},
_51
})
_51
_51
_51
// Check if there are any previous uploads to continue.
_51
return upload.findPreviousUploads().then(function (previousUploads) {
_51
// Found previous uploads so we select the first one.
_51
if (previousUploads.length) {
_51
upload.resumeFromPreviousUpload(previousUploads[0])
_51
}
_51
_51
// Start the upload
_51
upload.start()
_51
})
_51
})
_51
}

Upload URL

When uploading using the resumable upload endpoint, the storage server creates a unique URL for each upload, even for multiple uploads to the same path. All chunks will be uploaded to this URL using the PATCH method.

This unique upload URL will be valid for up to 24 hours. If the upload is not completed within 24 hours, the URL will expire and you'll need to start the upload again. TUS client libraries typically create a new URL if the previous one expires.

Concurrency

When two or more clients upload to the same upload URL only one of them will succeed. The other clients will receive a 409 Conflict error. Only 1 client can upload to the same upload URL at a time which prevents data corruption.

When two or more clients upload a file to the same path using different upload URLs, the first client to complete the upload will succeed and the other clients will receive a 409 Conflict error.

If you provide the x-upsert header the last client to complete the upload will succeed instead.

UppyJS example

You can check a full example using UppyJS.

UppyJS has integrations with different frameworks:

Overwriting files

When uploading a file to a path that already exists, the default behavior is to return a 400 Asset Already Exists error. If you want to overwrite a file on a specific path you can set the x-upsert header to true.

We do advise against overwriting files when possible, as the CDN will take some time to propagate the changes to all the edge nodes leading to stale content. Uploading a file to a new path is the recommended way to avoid propagation delays and stale content.

To learn more, see the CDN guide.