Storage Uploads
Supabase Storage provides two methods for uploading files:
- Standard Uploads
- Resumable Uploads
Standard Upload#
The standard file upload method is ideal for small files that are not larger than 6MB.
It uses the traditional multipart/form-data
format and is simple to implement using the supabase-js SDK. Here's an example of how to upload a file using the standard upload method:
note
You can upload up to 5GB file size using the standard upload method.
For files greater than 6 MB in size, use TUS Resumable Upload for better reliability.
_14import { createClient } from '@supabase/supabase-js'_14_14// Create Supabase client_14const supabase = createClient('your_project_url', 'your_supabase_api_key')_14_14// Upload file using standard upload_14async function uploadFile(file) {_14 const { data, error } = await supabase.storage.from('bucket_name').upload('file_path', file)_14 if (error) {_14 // Handle error_14 } else {_14 // Handle success_14 }_14}
Resumable Upload#
note
Resumable upload is in Beta. We are rolling this feature gradually, please contact us if you want to be prioritized.
The Resumable upload method is recommended for uploading large files that may exceed 6MB in size or for scenarios where network stability is a concern or if you simply want to have a progress bar 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
:
_49const tus = require('tus-js-client')_49_49const projectId = ''_49const token = ''_49_49function uploadFile(bucketName, fileName, file) {_49 return new Promise((resolve, reject) => {_49 var upload = new tus.Upload(file, {_49 endpoint: `https://${projectId}.supabase.co/storage/v1/upload/resumable`,_49 retryDelays: [0, 3000, 5000, 10000, 20000],_49 headers: {_49 authorization: `Bearer ${token}`,_49 'x-upsert': 'true', // optionally set upsert to true to overwrite existing files_49 },_49 uploadDataDuringCreation: true,_49 metadata: {_49 bucketName: bucketName,_49 objectName: fileName,_49 contentType: 'image/png',_49 cacheControl: 3600,_49 },_49 chunkSize: 6 * 1024 * 1024, // NOTE: it must be set to 6MB (for now) do not change it_49 onError: function (error) {_49 console.log('Failed because: ' + error)_49 reject(error)_49 },_49 onProgress: function (bytesUploaded, bytesTotal) {_49 var percentage = ((bytesUploaded / bytesTotal) * 100).toFixed(2)_49 console.log(bytesUploaded, bytesTotal, percentage + '%')_49 },_49 onSuccess: function () {_49 // console.log(upload)_49 console.log('Download %s from %s', upload.file.name, upload.url)_49 resolve()_49 },_49 })_49_49 // Check if there are any previous uploads to continue._49 return upload.findPreviousUploads().then(function (previousUploads) {_49 // Found previous uploads so we select the first one._49 if (previousUploads.length) {_49 upload.resumeFromPreviousUpload(previousUploads[0])_49 }_49_49 // Start the upload_49 upload.start()_49 })_49 })_49}
Upload URL#
When uploading using the resumable upload endpoint, the TUS 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 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. The TUS client library will automatically create a new URL if the previous one expires.
Concurrency#
When two or more clients try to 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.
note
We do not yet support checksum validation for the uploaded chunks. This means if a client changes the file mid way through the upload, the final upload will be an amalgamation of both the files. This has to be done intentionally by the client and is unlikely to happen in normal circumstances.
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 Here
Framework integration for UppyJS:
Overwriting Files#
When uploading a file to a path that already exists, the default behavior is to return a 409 Conflict
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 sometime 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.
If you want to know more about our CDN, check the CDN guide.
Access Control with RLS Policies#
Both the standard file upload and TUS resumable file upload methods in Supabase Storage support Row-Level Security (RLS) policies. RLS allows you to define fine-grained access control rules to restrict access to files based on user roles, permissions, or other criteria. This ensures that your files are secure and accessible only to authorized users.
For more information on RLS policies, see the Storage Access Control guide.
Conclusion#
Supabase Storage provides multiple options for uploading files, including standard file upload and TUS resumable file upload, both of which use RLS policies for access control. Additionally, there are client-side libraries like Uppy-js that make it easy to implement TUS uploads in your application. Choose the upload method that best fits your needs based on file size, network stability, and other requirements.