Swift File Upload
Upload Files from Swift Using URLSession (iOS & macOS)
Upload files from Swift with URLSession multipart. No SDK, REST API, CDN delivery, prepaid credits.
On Apple platforms, URLSession is the right tool for uploading user files, and it covers the entire files.link flow with no Cocoapod and no Swift Package dependency. The AWSS3 pod drags in AWSCore and a stack of categories that bloat your app binary and complicate App Store review; files.link is three URLSession requests that your app already has the capability to make.
The critical Swift-specific detail is uploadTask(with:fromFile:). Unlike data(for:), an upload task backed by a file URL can run as a background URLSession, meaning a large photo or video keeps uploading even after the user backgrounds your app or the screen locks — exactly what user-generated content apps need. The three steps: POST metadata to /v1/files/{folderId} with the raw API key in the Authorization header (no Bearer prefix), read the presigned url and id from the urls array, PUT the file with an upload task, then POST { ids: [id] } to /v1/files/confirm-upload.
struct Slot: Decodable { let url: String; let id: String }
struct UploadResponse: Decodable { let success: Bool; let urls: [Slot] }
func upload(folderId: String, fileURL: URL) async throws -> String {
let key = ProcessInfo.processInfo.environment["FILESLINK_KEY"]!
var req = URLRequest(url: URL(string: "https://api.files.link/v1/files/\(folderId)")!)
req.httpMethod = "POST"; req.setValue(key, forHTTPHeaderField: "Authorization")
req.setValue("application/json", forHTTPHeaderField: "Content-Type")
req.httpBody = try JSONEncoder().encode(["name": fileURL.lastPathComponent])
let (d, _) = try await URLSession.shared.data(for: req)
let slot = try JSONDecoder().decode(UploadResponse.self, from: d).urls[0]
var put = URLRequest(url: URL(string: slot.url)!); put.httpMethod = "PUT"
_ = try await URLSession.shared.upload(for: put, fromFile: fileURL)
var confirm = URLRequest(url: URL(string: "https://api.files.link/v1/files/confirm-upload")!)
confirm.httpMethod = "POST"; confirm.setValue(key, forHTTPHeaderField: "Authorization")
confirm.setValue("application/json", forHTTPHeaderField: "Content-Type")
confirm.httpBody = try JSONEncoder().encode(["ids": [slot.id]])
_ = try await URLSession.shared.data(for: confirm)
return slot.id
}From SwiftUI, call this inside a Task and feed the resulting CDN URL straight into AsyncImage. The same code compiles unchanged for macOS, watchOS, and tvOS. One important security note: a shipped iOS app cannot hide an embedded API key from a determined attacker, so for production consumer apps mint upload credentials from your own backend rather than baking the master key into the binary. Files are encrypted at rest, visibility is per file, and billing is prepaid credits.
Benefits With No Complexity
Global CDN delivery
Edge-cached worldwide
Signed-URL security
What You Get
Unlimited files
Unlimited storage
Public + Private storage
CDN ready links
Prepaid credits
More coming soon
How files.link Works
1. Upload
2. Copy
3. Use Anywhere
Why Developers Choose files.link
A Better Way to Store & Deliver Files
| AWS S3 (AWSS3 pod) | Firebase Storage SDK | files.link | |
|---|---|---|---|
| Works with URLSession (no pod / SPM dependency) | |||
| Background uploads via upload(fromFile:) | |||
| Global CDN delivery on every file | |||
| Smaller app binary (no vendor framework) | |||
| Prepaid credits (no surprise bills) |
Calculate Your Needs
Storage
Egress
CDN Bandwidth
Upload Files from Swift
- Global CDN delivery
- Edge-cached worldwide
- Signed-URL security
- Unlimited files
- Unlimited storage
- Public + Private storage
- No subscription — prepaid credits keep spend predictable