Working with S3 and Cloud Storage in Rust: aws-sdk-s3 Library

Online Python Trainer for Beginners

Learn Python easily without overwhelming theory. Solve practical tasks with automatic checking, get hints in Russian, and write code directly in your browser — no installation required.

Start Course

Working with S3 and Cloud Storage in Rust: aws-sdk-s3



Cloud object storage compatible with Amazon S3 has become the de facto standard for storing files, backups, static assets, and data. In the Rust ecosystem, the official AWS SDK for Rust — aws-sdk-s3 — is used for working with S3. This tool allows you to connect not only to Amazon S3 but also to any S3-compatible storage: MinIO, Yandex Object Storage, DigitalOcean Spaces, Cloudflare R2, and others.



Installation and Configuration



Add the following dependencies to Cargo.toml:



[dependencies]aws-sdk-s3 = "1.15"aws-config = "1.1"tokio = { version = "1", features = ["full"] }anyhow = "1.0"


For authentication, you can use environment variables, the AWS configuration file (~/.aws/credentials), or pass keys programmatically. A minimal client initialization looks like this:



use aws_sdk_s3::Client;use aws_config::meta::region::RegionProviderChain;

#[tokio::main]async fn main() -> Result<(), anyhow::Error> { let region_provider = RegionProviderChain::default_provider() .or_else("ru-central1"); let config = aws_config::from_env() .region(region_provider) .load() .await; let client = Client::new(&config); // Then work with client Ok(())}


Basic S3 Operations



Creating a Bucket



use aws_sdk_s3::model::BucketLocationConstraint;

let bucket_name = "my-rust-bucket";let constraint = BucketLocationConstraint::from("ru-central1");let _ = client .create_bucket() .bucket(bucket_name) .create_bucket_configuration( aws_sdk_s3::model::CreateBucketConfiguration::builder() .location_constraint(constraint) .build() ) .send() .await?;


Uploading a File (PutObject)



use aws_sdk_s3::primitives::ByteStream;use std::path::Path;

let file_path = "local_file.txt";let body = ByteStream::from_path(Path::new(file_path)).await?;

client .put_object() .bucket(bucket_name) .key("uploads/remote_file.txt") .body(body) .send() .await?;println!("File uploaded");


Downloading a File (GetObject)



use tokio::io::AsyncWriteExt;

let resp = client .get_object() .bucket(bucket_name) .key("uploads/remote_file.txt") .send() .await?;

let mut file = tokio::fs::File::create("downloaded.txt").await?;let mut stream = resp.body;while let Some(chunk) = stream.try_next().await? { file.write_all(&chunk).await?;}println!("File downloaded");


Listing Objects in a Bucket



let objects = client    .list_objects_v2()    .bucket(bucket_name)    .prefix("uploads/")    .send()    .await?;

for obj in objects.contents().unwrap_or_default() { println!("- {}", obj.key().unwrap_or("unknown"));}


Connecting to MinIO and Other S3-Compatible Storage



To work with MinIO (or any other non-AWS storage), you need to override the endpoint and disable region signature verification (if required). Here is a complete example:



use aws_sdk_s3::{Client, Config, Credentials, Region};use aws_smithy_client::erase::DynConnector;use aws_smithy_client::hyper_ext;use http::Uri;

let creds = Credentials::new( "minioadmin", "minioadmin", None, None, "minio",);

let endpoint = Uri::from_static("http://localhost:9000");let region = Region::new("us-east-1");

let config = Config::builder() .credentials_provider(creds) .region(region) .endpoint_resolver(endpoint) .force_path_style(true) // Important for MinIO .build();

let client = Client::from_conf(config);// All operations with client now go through MinIO


Please note

Recommendations