Upload files
Implement upload functionality
Upload from file
When you have a file that you want to upload, you can specify the url to the file in the local parameter.
If a file with the same path already exists in S3, the existing S3 file will be overwritten.
let dataString = "My Data"let fileName = "myFile.txt"guard let fileUrl = FileManager.default.urls( for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent(fileName)else { return }
try dataString.write( to: fileUrl, atomically: true, encoding: .utf8)
let uploadTask = Amplify.Storage.uploadFile( path: .fromString("public/example/path/myFile.txt"), local: fileUrl)Upload from data
To upload a file from a data object, specify the path and the data object to be uploaded.
let dataString = "My Data"let data = Data(dataString.utf8)let uploadTask = Amplify.Storage.uploadData( path: .fromString("public/example/path/myFile.txt"), data: data)Upload to a specified bucket
You can perform an upload operation to a specific bucket by providing the bucket option.
You can use .fromOutputs(name:) to provide a string representing the target bucket's assigned name in the Amplify Backend.
// Upload from Filelet uploadTask = Amplify.Storage.uploadFile( path: .fromString("public/example/path/myFile.txt"), local: fileUrl, options: .init( bucket: .fromOutputs(name: "secondBucket") ))
// Upload from Datalet uploadTask = Amplify.Storage.uploadData( path: .fromString("public/example/path/myFile.txt"), data: data, options: .init( bucket: .fromOutputs(name: "secondBucket") ))You can also use .fromBucketInfo(_:) to provide a bucket name and region directly.
// Upload from Filelet uploadTask = Amplify.Storage.uploadFile( path: .fromString("public/example/path/myFile.txt"), local: fileUrl, options: .init( bucket: .fromBucketInfo(.init( bucketName: "another-bucket-name", region: "another-bucket-region") ) ))
// Upload from Datalet uploadTask = Amplify.Storage.uploadData( path: .fromString("public/example/path/myFile.txt"), data: data, options: .init( bucket: .fromBucketInfo(.init( bucketName: "another-bucket-name", region: "another-bucket-region") ) ))Monitor upload progress
To track progress of the upload, use the reference returned by the uploadFile or uploadData as shown below.
Task { for await progress in await uploadTask.progress { print("Progress: \(progress)") }}
let value = try await uploadTask.valueprint("Completed: \(value)")let progressSink = uploadTask .inProcessPublisher .sink { progress in print("Progress: \(progress)") }
let resultSink = uploadTask .resultPublisher .sink { if case let .failure(storageError) = $0 { print("Failed: \(storageError.errorDescription). \(storageError.recoverySuggestion)") } } receiveValue: { data in print("Completed: \(data)") }Pause, resume, and cancel uploads
Calls to uploadData or uploadFile return a reference to the task that is actually performing the upload.
You can pause then resume the task or cancel a task as shown below.
uploadTask.pause()uploadTask.resume()uploadTask.cancel()All upload options
| Option | Type | Description |
|---|---|---|
| metadata | [String: String] | Metadata for the object to store. |
| contentType | String | The standard MIME type describing the format of the object to store. |
| bucket | StorageBucket | The bucket in which the object should be stored |
Working with Security Scoped Resources (from iCloud)
Security scoped resources refer to files that are retrieved from iCloud or other cloud storage providers. You're likely to run into these file types when using system components that provide access to files stored in iCloud, e.g. UIDocumentBrowserViewController.
To upload security scoped resources, you'll need to:
- use startAccessingSecurityScopedResource() and stopAccessingSecurityScopedResource() to access the data within security scoped files
- temporarily persist the data from the security scoped files in your app's sandbox
- upload files using the temporary URLs
- delete temporarily persisted files (optional)
struct ScopedResourceFile { let name: String let data: Data}
func getTempUrls(securityScopedUrls: [URL]) -> [URL] { // 1. get the content of security scoped resources into ScopedResourceFile struct let fileContents = securityScopedUrls.compactMap { url -> ScopedResourceFile? in let startAccess = url.startAccessingSecurityScopedResource() guard startAccess else { print("Issue accessing security scoped resource at :\(url)") return nil } defer { url.stopAccessingSecurityScopedResource() } do { let data = try Data(contentsOf: url) let fileName = url.lastPathComponent return ScopedResourceFile(name: fileName, data: data) } catch { print("Couldn't create Data from contents of file at url: \(url)") return nil } }
// 2. write the file contents to temporary files and return the URLs of the temp files let localFileURLs = persistTemporaryFiles(fileContents)
// 3. Now you have local URLs for the files you'd like to upload. return localFileURLs}Upload using a presigned URL
You can use the getURL API with method: .put to generate a presigned URL for uploading files directly to S3. This is useful when:
- You need to integrate with third-party tools or libraries that only accept standard HTTP URL endpoints
- You want to share a temporary upload link with another client or service
- You need to upload from a context where the Amplify SDK is not available
import Amplifyimport AWSS3StoragePlugin
// Generate a presigned URL for uploadinglet uploadUrl = try await Amplify.Storage.getURL( path: .fromString("public/uploads/photo.jpg"), options: .init( pluginOptions: AWSStorageGetURLOptions( method: .put ) ))Then use the presigned URL to upload the file with a standard HTTP PUT request:
var request = URLRequest(url: uploadUrl)request.httpMethod = "PUT"request.httpBody = imageData
let (_, response) = try await URLSession.shared.data(for: request)let httpResponse = response as? HTTPURLResponseprint("Upload status: \(httpResponse?.statusCode ?? 0)")Presigned URL upload options
| Option | Type | Default | Description |
|---|---|---|---|
| pluginOptions.method | StorageAccessMethod | .get | .get generates a download URL. .put generates an upload URL. |
| expires | Int | 18000 | Number of seconds before the URL expires. |
| bucket | StorageBucket | Default bucket from Amplify configuration | The bucket in which the object is stored. |
| pluginOptions.validateObjectExistence | Bool | false | Whether to check the object exists before generating the URL. Skipped when method is .put. |
MultiPart upload
Amplify will automatically perform an Amazon S3 multipart upload for objects that are larger than 5MB. For more information about S3's multipart upload, see Uploading and copying objects using multipart upload