Amazon S3
file upload
C#
cloud storage
tutorial

How to upload a file to amazon S3 super easy using c

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

Uploading a file to Amazon S3 from C# is straightforward once you use the AWS SDK and stop trying to handcraft raw HTTP requests. The normal workflow is to create an AmazonS3Client, choose a bucket and key, and upload either with PutObjectAsync for direct control or TransferUtility for a more convenient file-oriented API.

Install the S3 SDK Package

In a .NET project, add the S3 package first:

bash
dotnet add package AWSSDK.S3

The AWS SDK will use the normal credential resolution chain, which means you should prefer configured environment credentials, IAM roles, or shared AWS profiles instead of hardcoding keys in the source.

Minimal Upload With PutObjectAsync

For a simple local file upload, PutObjectAsync is enough.

csharp
1using Amazon.S3;
2using Amazon.S3.Model;
3
4var s3 = new AmazonS3Client();
5
6var request = new PutObjectRequest
7{
8    BucketName = "my-bucket",
9    Key = "uploads/report.txt",
10    FilePath = "./report.txt",
11    ContentType = "text/plain"
12};
13
14var response = await s3.PutObjectAsync(request);
15Console.WriteLine($"HTTP status: {response.HttpStatusCode}");

This uploads report.txt from your local filesystem to the object key uploads/report.txt.

The bucket must already exist, and the credentials used by the client must have permission to write to it.

Use TransferUtility for Convenience

If your main use case is simply "upload this file," TransferUtility is even easier to read.

csharp
1using Amazon.S3;
2using Amazon.S3.Transfer;
3
4var s3 = new AmazonS3Client();
5var transfer = new TransferUtility(s3);
6
7await transfer.UploadAsync("./photo.jpg", "my-bucket", "images/photo.jpg");
8Console.WriteLine("Upload complete");

This is a good default for many applications because it removes some boilerplate. For larger transfers and higher-level workflows, it is often the cleaner API.

Choose the Region and Credentials Intentionally

The default client constructor works only if the environment is already configured correctly. If you need to target a specific region explicitly, pass it in.

csharp
1using Amazon;
2using Amazon.S3;
3
4var s3 = new AmazonS3Client(RegionEndpoint.USEast1);

In local development, common credential sources are:

  • 'aws configure profile data'
  • environment variables such as AWS_ACCESS_KEY_ID
  • IAM roles when running inside AWS

Avoid this pattern in real code:

csharp
new AmazonS3Client("ACCESS_KEY", "SECRET_KEY", RegionEndpoint.USEast1)

It works technically, but hardcoded secrets are a security liability.

Set Metadata When It Matters

S3 objects often need more than just bytes. You may want to set content type, cache headers, or custom metadata during upload.

csharp
1using Amazon.S3;
2using Amazon.S3.Model;
3
4var request = new PutObjectRequest
5{
6    BucketName = "my-bucket",
7    Key = "documents/manual.pdf",
8    FilePath = "./manual.pdf",
9    ContentType = "application/pdf"
10};
11
12request.Metadata.Add("uploaded-by", "my-app");
13
14var response = await s3.PutObjectAsync(request);
15Console.WriteLine(response.HttpStatusCode);

This matters because downstream browsers and applications often rely on the stored metadata to decide how to treat the object.

Check for Failures Cleanly

An S3 upload can fail because of permissions, region mismatches, missing buckets, or invalid paths. Catch the AWS exception type so you get useful diagnostics.

csharp
1using Amazon.S3;
2using Amazon.S3.Model;
3
4try
5{
6    var s3 = new AmazonS3Client();
7    await s3.PutObjectAsync(new PutObjectRequest
8    {
9        BucketName = "my-bucket",
10        Key = "uploads/report.txt",
11        FilePath = "./report.txt"
12    });
13}
14catch (AmazonS3Exception ex)
15{
16    Console.WriteLine($"S3 error: {ex.Message}");
17}

This is much better than treating every upload failure as a generic file or network problem.

Common Pitfalls

  • Hardcoding AWS keys in source code is a security mistake. Prefer profiles, environment variables, or IAM roles.
  • Forgetting to set the correct region can lead to confusing errors even when the bucket name and credentials look right.
  • Uploading without ContentType can make browsers or downstream systems interpret the file incorrectly.
  • Using a local file path that does not exist produces a client-side failure before S3 even sees the request.
  • Assuming bucket creation happens automatically is incorrect. The target bucket must already exist and be writable by your credentials.

Summary

  • Use the AWS SDK for .NET rather than building raw HTTP uploads yourself.
  • 'PutObjectAsync is the direct low-level approach, while TransferUtility is often the easiest file-upload API.'
  • Configure region and credentials intentionally, and never hardcode secrets in normal code.
  • Set metadata such as ContentType when the uploaded file needs to be served correctly later.
  • Catch AmazonS3Exception so upload failures are easy to diagnose.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.