Azure Blob Storage vs AWS S3 vs MinIO in .NET: Which Object Storage Should Your Team Use in 2026?

Search for a command to run...

No comments yet. Be the first to comment.
Retrieval-Augmented Generation lives or dies on one unglamorous step, and it is not the model or the vector database. It is chunking. When you get chunking documents for RAG in .NET wrong, the model r

Most teams reach for caching the moment an API gets slow, wire up Redis or output caching, and move on. But there is an older, lighter mechanism built into HTTP itself that solves two problems at once

If you shipped an AI agent in .NET over the last two years, there is a good chance it runs on Semantic Kernel. That was the right call at the time. But with Microsoft Agent Framework reaching GA in Ap

The first time an AI feature I shipped went down in production, nothing in my code had changed. The model provider had a bad afternoon: a wave of 429 Too Many Requests, then a stretch of 503s, and eve

If you have tried to add OpenTelemetry.Extensions.Logging to a .NET project, you already know how this ends. The restore fails, NuGet tells you the package cannot be found, and you start second-guessi

Coding Droplets
297 posts
Coding Droplets is your go-to resource for .NET and ASP.NET Core development. Whether you're just starting out or building production systems, you'll find practical guides, real-world patterns, and clear explanations that actually make sense.
From beginner-friendly tutorials to advanced architecture decisions. We publish fresh .NET content every day to help you grow at every stage of your career.
When a .NET team needs to store and serve files — user uploads, generated reports, media assets, audit exports — the first real decision is which object storage provider to wire into the application. Azure Blob Storage, AWS S3, and MinIO each have legitimate claims on your stack, and the right choice depends on deployment context, team ecosystem, portability goals, and how you want to structure your service layer in ASP.NET Core.
This comparison cuts through the marketing and focuses on what .NET developers actually care about: SDK maturity, dependency injection integration, local development experience, and the trade-offs that surface in real production systems. For developers who want to go deeper on production-ready patterns and see these integrations wired into a complete ASP.NET Core project, Patreon has the annotated source code with full error handling and lifecycle management.
All three services store unstructured data as objects inside containers (or buckets). The surface API is similar — upload, download, delete, generate pre-signed URLs — but the integration experience in .NET diverges significantly.
Azure.Storage.Blobs (the v12 SDK). First-class integration with Azure services including Managed Identity, App Configuration, and Key Vault.AWSSDK.S3 (or the newer AWSSDK.Extensions.NETCore.Setup for DI). The de facto standard for multi-cloud portability given the S3 API's industry adoption.Minio .NET client or AWSSDK.S3 pointed at a MinIO endpoint. The go-to for on-premises and air-gapped environments.The Azure.Storage.Blobs package offers first-class support for the Microsoft.Extensions.DependencyInjection container. You register BlobServiceClient as a singleton and inject it wherever file operations are needed. DefaultAzureCredential removes credential management from your application entirely when running on Azure infrastructure — no secrets in appsettings.json, no rotation scripts.
The SDK follows the Azure SDK design guidelines, which means consistent patterns across BlobContainerClient, BlobClient, and response types. Retry policies, transport options, and logging are all configurable at the client level and integrate with ILogger.
Where it falls short: the SDK is Azure-only. If you ever migrate away from Azure or want to run the same code against a local emulator (Azurite), you need conditional configuration. Testability requires either Azurite or a mock wrapper.
AWSSDK.S3 combined with AWSSDK.Extensions.NETCore.Setup gives you IAmazonS3 registered in the DI container with one line. Credentials flow through the SDK credential chain — environment variables, instance profiles, or explicit AWSCredentials — without touching your service code.
The SDK is battle-tested and deeply integrated into the AWS ecosystem. For teams already running on AWS, the combination of IAM policies, VPC endpoints, and S3 event notifications makes this the obvious choice. The SDK also supports TransferUtility for multipart uploads, which is the right path for large files.
The downside: the AWS SDK for .NET is large and opinionated. It pulls significant dependencies, and the API surface is broad. Teams who want a thin wrapper around file operations often end up building one anyway.
The Minio .NET client is lightweight and S3-compatible, but it does not integrate with the standard DI container as cleanly as the Azure or AWS SDKs out of the box. You typically register MinioClient as a singleton manually. Because MinIO implements the S3 API, you can also use AWSSDK.S3 against a MinIO endpoint, which gives you a consistent interface across your MinIO dev environment and AWS S3 production cluster.
MinIO's primary strength is local development and self-hosted deployment. Spinning up a MinIO container alongside your ASP.NET Core application in Docker Compose means your local environment behaves identically to production from a storage API perspective — something you cannot achieve with Azure Blob Storage without Azurite.
This question matters more than people realise at design time. A clean storage abstraction isolates your application from the provider decision entirely. You define an IFileStorageService interface with methods like UploadAsync, DownloadAsync, DeleteAsync, and GeneratePresignedUrlAsync, then inject an implementation backed by whichever provider fits your deployment.
The critical insight: AWS S3 and MinIO both implement the S3 protocol. This means a single implementation using IAmazonS3 can run against AWS in production and MinIO in development. Azure Blob Storage requires a separate implementation. Teams building multi-cloud or hybrid applications must account for this in their architecture.
| Provider | Local Emulator | DI Integration | Testability |
|---|---|---|---|
| Azure Blob Storage | Azurite (Docker) | First-class via BlobServiceClient |
Mock or Azurite |
| AWS S3 | MinIO (Docker) or LocalStack | Via AWSSDK.Extensions |
Mock or MinIO |
| MinIO | Native (Docker) | Manual registration | Direct — no emulator needed |
MinIO wins the local development story. It runs as a lightweight container, exposes the S3 API natively, and requires no account credentials or network access. For teams running integration tests in CI pipelines, MinIO is often the cleanest option — start the container, run the tests, tear it down. No cloud costs, no flaky network dependencies.
Azurite has improved significantly and is a credible local development story for Azure Blob Storage, but it does not fully cover all Blob Storage features, and some teams encounter subtle behavioural differences between Azurite and the real service.
BlobChangeLog or versioning features that Azure-specific tooling wraps well| Dimension | Azure Blob Storage | AWS S3 | MinIO |
|---|---|---|---|
| .NET SDK | Azure.Storage.Blobs (v12) |
AWSSDK.S3 |
Minio or AWSSDK.S3 |
| DI integration | First-class | Via AWSSDK.Extensions |
Manual |
| Auth model | DefaultAzureCredential, SAS tokens |
IAM roles, access keys | API key, IAM-compatible |
| Local dev | Azurite (Docker) | MinIO or LocalStack | Native MinIO |
| S3 API compatible | ❌ | ✅ | ✅ |
| Managed service | ✅ | ✅ | ❌ (self-hosted) |
| Multi-cloud portable | Limited | Yes (S3 standard) | Yes (S3-compatible) |
| Cost model | Per GB + operations | Per GB + operations | Infrastructure only |
| Best for | Azure-first teams | AWS teams, multi-cloud | On-prem, hybrid, local dev |
Credential rotation: Azure's Managed Identity means zero credentials in code and zero rotation ceremonies. AWS IAM instance profiles give you the same benefit on EC2 and ECS. MinIO requires API key management — something your team must operationalise, whether via Vault, Kubernetes secrets, or environment variable injection.
Pre-signed URLs: All three support them, but the URL format and signature algorithm differ. If your frontend directly uploads to or downloads from object storage, you are writing provider-specific URL generation logic. This is a real portability seam.
Multipart uploads for large files: All three support multipart upload. The SDK experience differs — Azure.Storage.Blobs handles chunking automatically in UploadAsync for large blobs. AWS TransferUtility is the recommended path. MinIO's client handles it transparently.
Cost at scale: MinIO on your own infrastructure is nearly free at scale (you pay for hardware and ops). Azure Blob and AWS S3 both have egress costs that become meaningful at high throughput. If your application serves large files to users frequently, egress pricing deserves a line in your architecture decision.
Yes — but it depends on your context.
If your team is Azure-native and does not have a strong multi-cloud mandate, Azure Blob Storage is the right answer. The SDK experience, Managed Identity integration, and seamless connection to the rest of the Azure stack make it the lowest-friction choice.
If your team is on AWS, building for multi-cloud, or wants the widest ecosystem compatibility, AWS S3 is the answer. Its API has become the industry standard for object storage, and the ecosystem around it is unmatched.
If you are deploying on-premises, building a product that runs in customer environments, or want an exceptional local development experience without cloud dependencies, MinIO is the answer. Its S3 compatibility also means you can swap to AWS S3 in the future without changing a line of application code — provided you used AWSSDK.S3 as the integration layer.
For most .NET SaaS products on a single cloud provider, the answer is simply: use whatever your cloud provider offers natively. The real architectural value comes from abstracting behind an IFileStorageService interface so the choice stays reversible.
Regardless of provider, a well-structured file storage integration in ASP.NET Core follows the same shape:
IFileStorageService interface in your Application layer with provider-agnostic method signaturesCancellationToken propagation on every async method — object storage calls are network I/O and must honour request cancellationThis structure means your application code never imports Azure.Storage.Blobs or AWSSDK.S3 directly. Only the Infrastructure project knows which provider is active. Swapping providers becomes a one-file configuration change.
☕ If this breakdown saved you a few hours of research, buy us a coffee — it keeps the content coming.
Yes, if your application uses AWSSDK.S3 or any S3-compatible client. MinIO implements the S3 API, so you can point your S3 client at a MinIO endpoint by overriding the ServiceURL in the AmazonS3Config. This makes MinIO the standard choice for local development when your production environment is AWS S3 — identical API surface, zero cloud costs, and no credentials required.
Register BlobServiceClient as a singleton using the connection string or DefaultAzureCredential in Program.cs. Microsoft publishes the Azure.Extensions.AspNetCore.Configuration.Secrets and Microsoft.Extensions.Azure packages that add AddAzureClients to the DI container, which is the idiomatic way to configure multiple Azure SDK clients with shared options and retry policies in one call.
No. MinIO is entirely self-hosted. You run it as a container (or binary) on your own infrastructure. There are no accounts, no API keys tied to external services, and no network requirements beyond your own network. This is what makes it attractive for on-premises deployments, regulated industries, and air-gapped environments.
All three support pre-signed URLs that grant temporary, scoped access to a specific object. The URL format and signing algorithm differ — S3 and MinIO use AWS Signature Version 4, while Azure Blob Storage uses SAS tokens with a different format. If your client-side code or frontend framework needs to generate or consume these URLs, you must use the correct SDK for each provider. Abstracting pre-signed URL generation behind your IFileStorageService interface insulates your application from this difference.
MinIO wins on developer experience. It runs as a lightweight Docker container with no external dependencies, exposes the full S3 API, and integrates directly into docker-compose.yml alongside your ASP.NET Core application and database. Azurite is a credible option for Azure Blob Storage teams but has coverage gaps. LocalStack supports AWS S3 but requires a paid tier for some features. If frictionless local development is a priority, structure your integration to use AWSSDK.S3 and point it at MinIO in development — then swap the endpoint to AWS S3 in production with no code changes.
For typical SaaS workloads — file uploads under 100MB, CDN-served downloads, background export jobs — the differences are negligible in isolation. At scale, AWS S3's request rate per prefix (with prefix sharding) and global CDN reach via CloudFront are well-understood and mature. Azure Blob Storage's Premium tier offers lower latency for small objects. MinIO performance is bounded by your hardware and network. Run your own benchmarks against your actual workload before making a decision based on performance claims alone.
Always. Even if you are certain you will never migrate providers, abstracting behind IFileStorageService makes your storage layer unit-testable with a mock, keeps provider-specific SDKs out of your application and domain layers, and documents the operations your application actually needs. The cost is negligible — one interface and one implementation — and the benefit of testability alone justifies it.