Rust File Upload
Upload Files From Rust With reqwest Multipart
Upload files from Rust with reqwest multipart. No SDK, REST API, CDN delivery, prepaid credits.
Pulling aws-sdk-s3 into a Rust project drags in a large dependency tree, a credential provider chain, and region/endpoint config before you've moved a byte. files.link is just HTTP, so the reqwest crate you probably already have covers the whole upload in three calls — and the same shape works with surf, ureq, or hyper if you prefer, on tokio, async-std, or the blocking client.
The flow: POST file metadata to /v1/files/{folderId} with your API key in the Authorization header (raw key, no Bearer prefix) to get back { success, urls: [{ url, id }] }; PUT the bytes to url; POST /v1/files/confirm-upload with { ids: [id] }. With async reqwest:
use reqwest::Client;
use serde_json::json;
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let api = "https://api.files.link";
let key = std::env::var("FILESLINK_KEY")?;
let folder = "your-folder-id";
let client = Client::new();
// 1. request a presigned PUT URL
let meta: serde_json::Value = client
.post(format!("{api}/v1/files/{folder}"))
.header("Authorization", &key)
.json(&json!({ "filesMetadata": [{ "name": "build.tar.gz" }] }))
.send().await?.json().await?;
let url = meta["urls"][0]["url"].as_str().unwrap();
let id = meta["urls"][0]["id"].as_str().unwrap();
// 2. upload the bytes
let bytes = tokio::fs::read("build.tar.gz").await?;
client.put(url).body(bytes).send().await?;
// 3. confirm
client.post(format!("{api}/v1/files/confirm-upload"))
.header("Authorization", &key)
.json(&json!({ "ids": [id] }))
.send().await?;
Ok(())
}No vendor crate, no credential chain — one header and three requests. For genuine multipart form bodies reqwest's multipart::Form is there, but the presigned PUT above is the simpler path for a single object. Because there's no SDK assuming a runtime, this compiles cleanly into a CLI tool, a background worker, or a WASM-adjacent service without fighting feature flags.
For large artifacts (up to 1TB) use the multipart upload endpoint: initiate, PUT each part to its presigned URL — futures::future::join_all lets you push parts concurrently — then complete, all without holding the whole file in memory. Confirmed public files come back as permanent CDN URLs; private files use signed URLs with a short expiry, selected at upload via a flag.
Billing is prepaid credits, so a misbehaving retry loop burns credits rather than opening an unbounded invoice. There's no official Rust SDK and you don't need one — the REST contract is the whole surface, and reqwest's strong typing via serde gives you the ergonomics an SDK would. If you also share Rust snippets, see the rust-paste page; for the cross-language endpoint reference, the cloud file storage API page covers every route.
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 (aws-sdk-s3) | Cloudinary | Backblaze B2 | files.link | |
|---|---|---|---|---|
| Works with reqwest / surf / ureq | ||||
| Runtime-agnostic (tokio / async-std / blocking) | ||||
| No credential provider chain | ||||
| Concurrent multipart up to 1TB | ||||
| Global CDN delivery included | ||||
| Public + signed URLs at upload time | ||||
| Prepaid credits, no surprise bills |
Calculate Your Needs
Storage
Egress
CDN Bandwidth
Upload Files from Rust
- Global CDN delivery
- Edge-cached worldwide
- Signed-URL security
- Unlimited files
- Unlimited storage
- Public + Private storage
- No subscription — prepaid credits keep spend predictable