In my chat application, I need reliable object storage for handling media and file uploads. Beyond that, I also need storage for backups, logs, and other critical data. Choosing the right storage solution turned out to be one of the hardest decisions. Each option I explored had its strengths and weaknesses, and finding the right balance for both development and production was challenging.
What is Object Storage?
Object storage is a way of storing and managing data as discrete units called objects. Unlike traditional file systems that organize data into hierarchical folders or block storage used for databases, object storage treats data as independent entities.
Each object consists of:
- The data itself (e.g., a file or media asset).
- Metadata that describes the object (e.g., file type, creation date, permissions).
- A unique identifier (an object ID or key) to access the object.
Object storage is ideal for unstructured data like images, videos, backups, and large datasets. It’s highly scalable, supports massive amounts of data, and is perfect for cloud-based applications.
What is the S3 API?
The S3 API is the industry-standard interface for interacting with object storage. Originally developed by Amazon Web Services for their Simple Storage Service (S3), the API has become widely adopted by other cloud and on-premise storage providers for compatibility.
Key features of the S3 API:
- RESTful Interface: You can use HTTP methods like
GET
,PUT
, andDELETE
to interact with storage. - Buckets and Objects: Data is organized in buckets (containers) and accessed using unique object keys.
- Access Control: Policies and permissions control who can access or manage data.
- Pre-Signed URLs: Temporarily generate secure links to private objects without exposing credentials.
- Versioning: Keep track of multiple versions of the same object.
Because the S3 API is standardized, many providers like Wasabi, MinIO, and Tigris offer S3-compatible endpoints, making it easy to switch between storage solutions without rewriting application logic.
Early Days with AWS S3
I initially used AWS S3, a widely popular object storage solution. S3 is reliable, feature-rich, and integrates seamlessly with most services. Its durability and scalability are unmatched. However, as I was working on a development phase and wasn’t ready to handle billing for production-grade infrastructure, I had to stop using S3.
While S3 is excellent, its pricing model (pay-per-use, including storage, egress, and API requests) can become expensive for smaller projects or during early development.
Blackblaze B2: Egress-Free but Limited
After leaving AWS, I turned to Blackblaze B2. The biggest appeal was that it offers egress-free pricing. This means you don’t get charged for downloading (egress) data, which can be a significant cost factor for object storage users.
However, Blackblaze B2 has a major limitation—it only operates in American data centers. For my project, this created high latency because my users and servers are located in other parts of the world. While its pricing was attractive, the performance wasn’t suitable for my use case.
Fly.io’s Tigris Storage: Global and Low-Latency
In the early stages of my project, I experimented with Fly.io, which offers a storage solution called Tigris. Tigris is a globally distributed, S3-compatible object storage service. It’s designed to provide low latency worldwide, making it great for applications with a global user base.
Tigris has some interesting features and pricing criteria:
- Data Storage: You pay based on the amount of data stored in buckets.
- Requests: Costs are calculated per request type and the quantity of requests.
- Data Transfer: Outbound data transfer (egress) costs are added to the bill.
While this approach works for small-scale usage, I was concerned about future scalability. As my app grows, the number of API requests to storage could become a significant cost driver. For this reason, I decided to explore other options.
MinIO: A Self-Hosted Option
I’ve always loved MinIO for its simplicity and open-source nature. It’s a great option for developers who want to run their own S3-compatible storage. However, deploying MinIO on the cloud can be expensive, especially for a small project in its development phase.
Self-hosting requires managing infrastructure and ensuring high availability, which wasn’t feasible for my current needs.
Wasabi: Egress-Free with a Caveat
Eventually, I settled on Wasabi as my storage solution. Like Blackblaze, Wasabi offers egress-free pricing, which means I don’t have to worry about costs when users download files. Wasabi’s performance has been solid, and its pricing is competitive.
However, there’s one major limitation: Wasabi doesn’t support public bucket permissions.
This limitation became a challenge for handling public files, such as user profile pictures or other assets meant for public access. For private files, I use pre-signed URLs, which allow my backend to generate temporary access links without exposing my bucket credentials. This means my backend doesn’t need to forward any files to the user for private content.
But for public files, since Wasabi doesn’t support public buckets, I had to create a backend service to forward these files to users. This extra layer adds redundancy and increases the load on my backend, which isn’t ideal. It introduces additional latency and consumes more server resources.
Despite this drawback, I made it work because Wasabi’s other benefits, like egress-free pricing and good performance, outweighed this issue for now.
Conclusion
Choosing the right object storage solution depends heavily on the specific needs of your project. While AWS S3 remains the gold standard for its reliability, rich feature set, and widespread compatibility, it can be cost-prohibitive for smaller projects or early development phases. Alternatives like Wasabi and Backblaze B2 offer egress-free models, making them more attractive for certain use cases, but they come with limitations like latency issues or lack of public bucket support.
Throughout this journey, I’ve realized that no single solution is perfect. For private files, pre-signed URLs work great, but for public assets, the lack of a public bucket feature in some services can add unnecessary complexity to the backend. Ultimately, balancing cost, performance, and functionality is key.
If your application relies on object storage, understanding the S3 API is essential, as it provides the flexibility to switch providers with minimal changes to your codebase. For now, I’ve settled on Wasabi. As the project grows, I may revisit other options to ensure scalability and performance align with future demands.