9 releases
Uses new Rust 2024
| new 0.1.8 | Jan 12, 2026 |
|---|---|
| 0.1.7 | Jan 12, 2026 |
#41 in HTTP client
4,494 downloads per month
440KB
11K
SLoC
s3-rs
Lean, modern, unofficial S3-compatible client for Rust.
Highlights
- Async + blocking clients (consistent API shape)
- Presigned URLs and multipart upload
- Optional checksums, tracing, and metrics
- Integration-tested against MinIO and RustFS
- Small dependency surface (feature-gated)
- Structured errors (status/code/request id/body snippet)
Install
# async + rustls (default)
cargo add s3
# blocking (disable defaults, pick one TLS backend)
cargo add s3 --no-default-features --features blocking,rustls
# async + native-tls
cargo add s3 --no-default-features --features async,native-tls
MSRV: Rust 1.92.
Usage
Async
use s3::{Auth, Client};
# async fn demo() -> Result<(), s3::Error> {
let client = Client::builder("https://s3.example.com")?
.region("us-east-1")
.auth(Auth::from_env()?)
.build()?;
let obj = client.objects().get("my-bucket", "path/to/object.txt").send().await?;
let bytes = obj.bytes().await?;
println!("{} bytes", bytes.len());
# Ok(())
# }
Auth::from_env() reads AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and optionally AWS_SESSION_TOKEN.
Blocking
use s3::{Auth, BlockingClient};
fn demo() -> Result<(), s3::Error> {
let client = BlockingClient::builder("https://s3.example.com")?
.region("us-east-1")
.auth(Auth::from_env()?)
.build()?;
let obj = client.objects().get("my-bucket", "path/to/object.txt").send()?;
let bytes = obj.bytes()?;
println!("{} bytes", bytes.len());
Ok(())
}
Configuration
use std::time::Duration;
use s3::{AddressingStyle, Auth, Client};
# async fn demo() -> Result<(), s3::Error> {
let client = Client::builder("https://s3.example.com")?
.region("us-east-1")
.auth(Auth::from_env()?)
.addressing_style(AddressingStyle::Auto)
.timeout(Duration::from_secs(30))
.max_attempts(3)
.build()?;
# Ok(())
# }
Presign
use s3::{Auth, Client};
# async fn demo() -> Result<(), s3::Error> {
let client = Client::builder("https://s3.example.com")?
.region("us-east-1")
.auth(Auth::from_env()?)
.build()?;
let presigned = client
.objects()
.presign_get("my-bucket", "path/to/object.txt")
.build()?;
println!("GET {}", presigned.url);
# Ok(())
# }
Endpoint presets (feature = providers)
use s3::{Auth, providers};
# async fn demo() -> Result<(), s3::Error> {
let preset = providers::minio_local();
let client = preset
.async_client_builder()?
.auth(Auth::from_env()?)
.build()?;
# Ok(())
# }
Authentication
Auth::Anonymous: unsigned requests (for public buckets / anonymous endpoints)Auth::from_env(): static credentials from env varsAuth::provider(...): plug in your own refreshable provider (cached/singleflight refresh)- Optional features:
credentials-profile: shared config/profile loadercredentials-imds: IMDS credentials (async/blocking APIs)credentials-sts: web identity / STS flows
Compatibility
- Addressing styles:
AddressingStyle::Auto(default),Path,VirtualHosted - Targets: any S3-compatible service; CI runs against MinIO and RustFS
Feature flags
- Modes:
async(default),blocking - TLS:
rustls(default),native-tls - Optional:
multipart,checksums,providers,credentials-profile,credentials-imds,credentials-sts,tracing,metrics
Examples
- Basic put/get/delete:
examples/async_put_get_delete.rs - Streaming upload (requires Content-Length):
examples/async_put_stream.rs - List objects v2 + pagination:
examples/async_list_objects.rs - Multipart upload (feature =
multipart):examples/async_multipart_upload.rs - Presign:
examples/presign_get.rs,examples/async_presign_build_async.rs - Blocking:
examples/blocking_put_get_delete.rs - More:
examples/README.md
Dependencies
~13–35MB
~574K SLoC