<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Ethan Carter</title>
    <description>The latest articles on DEV Community by Ethan Carter (@ethan-carter).</description>
    <link>https://dev.to/ethan-carter</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F3991599%2Fbb3daa8b-8625-441e-9a96-b832899e55b1.jpg</url>
      <title>DEV Community: Ethan Carter</title>
      <link>https://dev.to/ethan-carter</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/ethan-carter"/>
    <language>en</language>
    <item>
      <title>Multi-Cloud S3-Compatible Strategy: Avoiding Vendor Lock-In (2026)</title>
      <dc:creator>Ethan Carter</dc:creator>
      <pubDate>Fri, 14 Aug 2026 00:00:00 +0000</pubDate>
      <link>https://dev.to/ethan-carter/multi-cloud-s3-compatible-strategy-avoiding-vendor-lock-in-2026-59bn</link>
      <guid>https://dev.to/ethan-carter/multi-cloud-s3-compatible-strategy-avoiding-vendor-lock-in-2026-59bn</guid>
      <description>&lt;h1&gt;
  
  
  Multi-Cloud S3-Compatible Strategy: Avoiding Vendor Lock-In (2026)
&lt;/h1&gt;

&lt;p&gt;Most teams assume they're portable because their app talks the S3 API. That assumption breaks the first time a cloud jacks up prices or you actually need to leave. The API was never the trap. Everything built on top of it is.&lt;/p&gt;

&lt;p&gt;This is a practical guide to keeping the option to move, cheaply, without re-architecting your stack.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Lock-In Problem: Where S3 Actually Traps You
&lt;/h2&gt;

&lt;p&gt;S3 compatibility cuts both ways. Every vendor implements the core API, so your PutObject and GetObject calls port in theory. In practice, "portable in theory" falls apart two layers deeper, at the parts most teams never think about:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 1 is the API, and it's portable.&lt;/strong&gt; &lt;code&gt;put_object&lt;/code&gt; / &lt;code&gt;get_object&lt;/code&gt; work everywhere. No issue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 2 is non-standard features.&lt;/strong&gt; Lifecycle rules, Object Lock modes, S3 Select, bucket logging. The syntax differs per vendor. What works on AWS does not drop into MinIO or RustFS cleanly.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Layer 3 is ecosystem glue.&lt;/strong&gt; IAM, event routing (SQS/SNS/Lambda vs Pub/Sub vs Event Grid), monitoring (CloudWatch vs Stackdriver vs Azure Monitor), CI/CD wired to one CLI. None of it moves with your data.&lt;/p&gt;

&lt;p&gt;We've watched teams discover they were locked in at Layer 2 or 3, not Layer 1. The S3 API was fine. The forty other things they'd wired around it were not.&lt;/p&gt;

&lt;h2&gt;
  
  
  A Portable S3 Architecture
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Abstract the endpoint from day one
&lt;/h3&gt;

&lt;p&gt;Don't hardcode &lt;code&gt;s3.us-east-1.amazonaws.com&lt;/code&gt;. Every S3 SDK takes an &lt;code&gt;endpoint_url&lt;/code&gt;. Use it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;os&lt;/span&gt;
&lt;span class="n"&gt;s3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;s3&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;endpoint_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;S3_ENDPOINT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;   &lt;span class="c1"&gt;# https://s3.us-east-1.amazonaws.com or http://localhost:9000
&lt;/span&gt;    &lt;span class="n"&gt;aws_access_key_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS_ACCESS_KEY_ID&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
    &lt;span class="n"&gt;aws_secret_access_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;os&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;environ&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;AWS_SECRET_ACCESS_KEY&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That single line is the difference between "we can move if we must" and "we're stuck."&lt;/p&gt;

&lt;h3&gt;
  
  
  Stick to core operations
&lt;/h3&gt;

&lt;p&gt;If portability matters, restrict yourself to what every serious S3 implementation actually supports:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Safe (universal)&lt;/th&gt;
&lt;th&gt;Caution (varies)&lt;/th&gt;
&lt;th&gt;Avoid (vendor-specific)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;PutObject / GetObject&lt;/td&gt;
&lt;td&gt;Lifecycle rules&lt;/td&gt;
&lt;td&gt;Event notifications (SQS/Lambda)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ListObjectsV2&lt;/td&gt;
&lt;td&gt;Object Lock modes&lt;/td&gt;
&lt;td&gt;IAM-policy access&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;DeleteObject&lt;/td&gt;
&lt;td&gt;S3 Select&lt;/td&gt;
&lt;td&gt;KMS-managed keys&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Multipart Upload&lt;/td&gt;
&lt;td&gt;Bucket logging&lt;/td&gt;
&lt;td&gt;Requester-pays&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;HeadObject&lt;/td&gt;
&lt;td&gt;Presigned URL quirks&lt;/td&gt;
&lt;td&gt;Cross-account roles&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CopyObject&lt;/td&gt;
&lt;td&gt;Replication config&lt;/td&gt;
&lt;td&gt;Glacier retrieval tiers&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Rule of thumb: if it isn't in the MinIO + RustFS + Ceph RGW docs, assume it won't move.&lt;/p&gt;

&lt;h3&gt;
  
  
  Own your orchestration layer
&lt;/h3&gt;

&lt;p&gt;Stop reaching for cloud-native orchestration for anything S3-critical:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Function&lt;/th&gt;
&lt;th&gt;Cloud-native (locked)&lt;/th&gt;
&lt;th&gt;Portable&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Workflows&lt;/td&gt;
&lt;td&gt;Step Functions / Logic Apps&lt;/td&gt;
&lt;td&gt;Airflow / Dagster&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ETL&lt;/td&gt;
&lt;td&gt;Glue DataBrew&lt;/td&gt;
&lt;td&gt;dbt / Spark&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Catalog&lt;/td&gt;
&lt;td&gt;Glue Catalog&lt;/td&gt;
&lt;td&gt;Iceberg (metadata lives in S3)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Scheduling&lt;/td&gt;
&lt;td&gt;EventBridge / CloudWatch Cron&lt;/td&gt;
&lt;td&gt;Airflow DAGs / cron&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Secrets&lt;/td&gt;
&lt;td&gt;Secrets Manager / Key Vault&lt;/td&gt;
&lt;td&gt;Vault / env vars&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Test portability every quarter
&lt;/h3&gt;

&lt;p&gt;Don't wait for a forced migration to learn you weren't portable:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Stand up MinIO or &lt;a href="https://rustfs.com" rel="noopener noreferrer"&gt;RustFS&lt;/a&gt; in Docker (under a minute).&lt;/li&gt;
&lt;li&gt;Point staging at it.&lt;/li&gt;
&lt;li&gt;Run your suite.&lt;/li&gt;
&lt;li&gt;Write down what broke.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Costs a couple of hours a quarter. Beats finding out during a six-month migration with a real egress bill attached.&lt;/p&gt;

&lt;h2&gt;
  
  
  Self-Hosting: Maximum Portability
&lt;/h2&gt;

&lt;p&gt;The most portable setup is running your own S3 everywhere:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Region A (AWS us-east-1)   → RustFS on EC2
Region B (Azure westeurope) → RustFS on Azure VMs
Region C (GCP asia-east1)  → RustFS on GCE
On-prem (Tokyo)            → RustFS on bare metal
Edge (stores)              → RustFS on ARM
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Same binary, same API, same ops model. You kill the egress between your own regions, you control the upgrade cadence, and your data stays where you put it. The trade is that you run it. If you already operate K8s, Postgres, and app servers in each region, adding S3 is incremental. Not a new skill.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Multi-Cloud Is a Waste of Time
&lt;/h2&gt;

&lt;p&gt;Honest boundaries:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Scenario&lt;/th&gt;
&lt;th&gt;Verdict&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Under 5TB&lt;/td&gt;
&lt;td&gt;Don't bother. Migration cost beats the savings.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Under 5 engineers&lt;/td&gt;
&lt;td&gt;Don't bother. Ops overhead beats the option value.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Heavy Lambda / SageMaker / BigQuery use&lt;/td&gt;
&lt;td&gt;Partial. Storage moves, compute doesn't.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Regulatory region lock&lt;/td&gt;
&lt;td&gt;Comply. Law beats preference.&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Early-stage startup&lt;/td&gt;
&lt;td&gt;Ship first. Revisit at Series B.&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;Lock-in lives at Layers 2 and 3 (features + ecosystem), not Layer 1 (the API).&lt;/li&gt;
&lt;li&gt;Abstract &lt;code&gt;endpoint_url&lt;/code&gt; from day one. Never hardcode a region endpoint.&lt;/li&gt;
&lt;li&gt;Use core S3 operations only. Test against MinIO/RustFS every quarter.&lt;/li&gt;
&lt;li&gt;Own your orchestration (Airflow/dbt/Iceberg beat Step Functions/Glue).&lt;/li&gt;
&lt;li&gt;Self-hosted S3 across regions is max portability. Same binary, different tin.&lt;/li&gt;
&lt;li&gt;Multi-cloud isn't free. Pay for it only when the option value beats the ops cost.&lt;/li&gt;
&lt;/ol&gt;




&lt;p&gt;&lt;em&gt;RustFS runs identically on AWS, Azure, GCP, and bare metal. One binary, any infrastructure, Apache 2.0. &lt;a href="https://rustfs.com/download" rel="noopener noreferrer"&gt;Download&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;




&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is the S3 API actually portable between clouds?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Core operations (PutObject, GetObject, ListObjects, Multipart Upload) are genuinely portable. They behave identically across AWS S3, MinIO, RustFS, Ceph RGW, and Wasabi. But roughly a third of the full S3 surface is vendor extensions (event notifications, specialized encryption, IAM, request-payer config) that don't transfer. For apps using core operations only, portability is real. For apps wired into one cloud's ecosystem, it's an illusion.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How much does multi-cloud storage cost versus single-cloud?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Self-hosted S3 (RustFS or MinIO) on cheap VMs across regions usually runs 40 to 70 percent under each cloud's native service. You drop per-GB premiums, cross-instance egress, and request fees, but you pick up ops overhead. Running multiple clouds' native S3 at once normally costs more than single-cloud, because of redundant storage plus cross-cloud egress. The cheapest pattern is self-hosted S3 on the cheapest VM in each region.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the fastest way to test S3 portability?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Stand up MinIO (&lt;code&gt;docker run -p 9000:9000 minio/minio server /data&lt;/code&gt;) or RustFS in Docker, point &lt;code&gt;S3_ENDPOINT&lt;/code&gt; at localhost:9000, and run your suite. If 95 percent plus passes with no code changes, you're portable. Document the failures, because those are your lock-in points. Do it quarterly. About two hours, versus weeks of firefighting and five-figure egress during a forced move.&lt;/p&gt;

</description>
      <category>s3</category>
      <category>multicloud</category>
      <category>vendorlockin</category>
      <category>rustfs</category>
    </item>
    <item>
      <title>S3 Metadata: Indexing Billions of Objects Without Falling Over</title>
      <dc:creator>Ethan Carter</dc:creator>
      <pubDate>Wed, 12 Aug 2026 15:29:51 +0000</pubDate>
      <link>https://dev.to/ethan-carter/s3-metadata-indexing-billions-of-objects-without-falling-over-15ob</link>
      <guid>https://dev.to/ethan-carter/s3-metadata-indexing-billions-of-objects-without-falling-over-15ob</guid>
      <description>&lt;h1&gt;
  
  
  S3 Metadata: Indexing Billions of Objects Without Falling Over
&lt;/h1&gt;

&lt;p&gt;If you operate S3-compatible storage at scale, slow ListObjectsV2 requests will eventually find you. Stay under your metadata threshold, and listings return fast. Cross it, and you'll watch timeouts, Slow Down errors, and after-hours alerts pile up.&lt;/p&gt;

&lt;p&gt;Every storage backend hits this wall at a different object count. Let's walk through what breaks, how popular systems behave, and practical fixes you can roll out.&lt;/p&gt;

&lt;h2&gt;
  
  
  What even is S3 metadata?
&lt;/h2&gt;

&lt;p&gt;When you upload an object to S3, two pieces get saved:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Your raw file data&lt;/li&gt;
&lt;li&gt;Object metadata — all descriptive information attached to that file&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Here's what metadata typically includes:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metadata Field&lt;/th&gt;
&lt;th&gt;Example&lt;/th&gt;
&lt;th&gt;Typical Size&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Object Key&lt;/td&gt;
&lt;td&gt;&lt;code&gt;logs/app/2026-07-24/abc123.log&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Variable (50–500 bytes)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Content Length&lt;/td&gt;
&lt;td&gt;&lt;code&gt;1234567 bytes&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;8 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Content-Type&lt;/td&gt;
&lt;td&gt;&lt;code&gt;application/json&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;~25 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ETag&lt;/td&gt;
&lt;td&gt;&lt;code&gt;"d41d8cd98f00b204e9800998ecf8427e"&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;36 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Last-Modified&lt;/td&gt;
&lt;td&gt;&lt;code&gt;2026-07-24T15:30:00Z&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;~24 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Storage Class&lt;/td&gt;
&lt;td&gt;&lt;code&gt;STANDARD&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;~12 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;User Tags&lt;/td&gt;
&lt;td&gt;&lt;code&gt;env=production&amp;amp;team=backend&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Up to 2KB (combined)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Custom Metadata Headers&lt;/td&gt;
&lt;td&gt;&lt;code&gt;x-amz-meta-owner:uid-12345&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;Up to 2KB (combined)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Version ID&lt;/td&gt;
&lt;td&gt;&lt;code&gt;RgvpLpBZLXhPvWXNk6H_8sN1FnNtIqF&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;~40 bytes&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Each object adds roughly 200–800 bytes of metadata overhead, stored separately from your actual data payload.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why LIST operations get painfully slow at scale
&lt;/h2&gt;

&lt;p&gt;Every ListObjectsV2 call forces the storage service to:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Scan its metadata index for keys matching your prefix and delimiter&lt;/li&gt;
&lt;li&gt;Apply filters and limits&lt;/li&gt;
&lt;li&gt;Sort matching keys lexicographically&lt;/li&gt;
&lt;li&gt;Paginate results (max 1,000 entries per page + continuation token)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;Real-world performance you'll observe (typical for naive prefix scans; your mileage varies with key layout and access patterns):&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Under 10k objects:&lt;/strong&gt; List calls finish in &amp;lt;100ms, no issues&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;~1M objects:&lt;/strong&gt; Queries take 1–5s depending on how narrow your prefix is&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;~100M objects:&lt;/strong&gt; Latency balloons to 10–60+ seconds, or requests timeout&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;1B+ objects:&lt;/strong&gt; Naive LIST calls aren't reliable anymore — you need a proper plan.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The real bottleneck isn't your file data
&lt;/h2&gt;

&lt;p&gt;The pain point is the metadata index. Major S3 implementations handle metadata very differently:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Implementation&lt;/th&gt;
&lt;th&gt;Metadata Design&lt;/th&gt;
&lt;th&gt;Scaling Behavior&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;AWS S3&lt;/td&gt;
&lt;td&gt;Proprietary distributed index&lt;/td&gt;
&lt;td&gt;Supports billions of objects; LIST throttling kicks in at extreme scale&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MinIO&lt;/td&gt;
&lt;td&gt;Object metadata in &lt;code&gt;xl.meta&lt;/code&gt; alongside data, with an in-cluster &lt;code&gt;.metacache&lt;/code&gt; + background scanner for LIST&lt;/td&gt;
&lt;td&gt;Scales into the hundreds of millions with selective prefixes; LIST at extreme scale depends on the metacache staying warm&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ceph RGW&lt;/td&gt;
&lt;td&gt;RADOS per-entry metadata&lt;/td&gt;
&lt;td&gt;Scales reasonably, but LIST linearly scans matching entries&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RustFS&lt;/td&gt;
&lt;td&gt;Embedded RocksDB + custom sharded index&lt;/td&gt;
&lt;td&gt;Built for scale — subsecond LIST with selective prefixes at 100M+ objects (validated in RustFS internal benchmarks)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SeaweedFS&lt;/td&gt;
&lt;td&gt;Filer + LevelDB/SQL backend&lt;/td&gt;
&lt;td&gt;Performance heavily depends on your database backend choice&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Actionable strategies for high-object-count buckets
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Strategy 1: Namespace partitioning (start here)
&lt;/h3&gt;

&lt;p&gt;The highest-impact change you can make: don't cram everything into one bucket.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Bad: One giant monolithic bucket
s3://prod-data/
├── logs/                    # 500M objects
├── user-uploads/            # 200M objects
├── ml-checkpoints/          # 50M objects
├── backups/                 # 10M objects
└── temp/                    # 5M objects
# Total: 765M objects. Every LIST scans every namespace.

# Better: Split workloads into dedicated buckets
s3://prod-logs/              # 500M objects (isolated metadata index)
s3://prod-uploads/           # 200M objects (isolated metadata index)
s3://prod-ml-checkpoints/    # 50M objects (isolated metadata index)
s3://prod-backups/           # 10M objects (isolated metadata index)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Each bucket runs its own independent metadata index. Listing inside &lt;code&gt;prod-uploads&lt;/code&gt; never touches metadata from your log bucket.&lt;/p&gt;

&lt;p&gt;Quick note on cost: AWS doesn't charge per bucket, and self-hosted S3 systems generally don't penalize extra buckets.&lt;/p&gt;

&lt;h3&gt;
  
  
  Strategy 2: Structure your object prefixes smartly
&lt;/h3&gt;

&lt;p&gt;Even within a single bucket, organized key paths drastically speed up prefix filtering.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;# Poor: Flat layout — LIST must scan everything
s3://bucket/object-000001.json
s3://bucket/object-000002.json

# Improved: Hierarchical prefixes narrow the scan range
s3://bucket/year=2026/month=07/day=24/hour=15/object-abc123.json
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A request using &lt;code&gt;Prefix="year=2026/month=07/"&lt;/code&gt; only loads metadata for July data, instead of your entire bucket.&lt;/p&gt;

&lt;h3&gt;
  
  
  Strategy 3: Avoid full-bucket scans at all costs
&lt;/h3&gt;

&lt;p&gt;This anti-pattern destroys performance on large buckets:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="c1"&gt;# ❌ Don't use this against large buckets — scans full metadata
&lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;list_objects_v2&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Bucket&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;my-bucket&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# ✅ Use targeted prefix pagination
&lt;/span&gt;&lt;span class="n"&gt;paginator&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get_paginator&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;list_objects_v2&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;paginator&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;paginate&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Bucket&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;my-bucket&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;logs/2026-07/&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
    &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;page&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;get&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;Contents&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;[]):&lt;/span&gt;
        &lt;span class="nf"&gt;process&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Strategy 4: Run an external metadata index
&lt;/h3&gt;

&lt;p&gt;Once you hit roughly 100M objects, maintain a separate metadata database alongside S3.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="c1"&gt;-- Sample schema for PostgreSQL / MySQL / SQLite external index&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;TABLE&lt;/span&gt; &lt;span class="n"&gt;s3_objects&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="k"&gt;key&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;PRIMARY&lt;/span&gt; &lt;span class="k"&gt;KEY&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;bucket&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt; &lt;span class="k"&gt;NOT&lt;/span&gt; &lt;span class="k"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="k"&gt;size&lt;/span&gt; &lt;span class="nb"&gt;BIGINT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;last_modified&lt;/span&gt; &lt;span class="n"&gt;TIMESTAMPTZ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;content_type&lt;/span&gt; &lt;span class="nb"&gt;TEXT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;tags&lt;/span&gt; &lt;span class="n"&gt;JSONB&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;created_at&lt;/span&gt; &lt;span class="n"&gt;TIMESTAMPTZ&lt;/span&gt; &lt;span class="k"&gt;DEFAULT&lt;/span&gt; &lt;span class="n"&gt;NOW&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;-- Indexes tuned for common queries&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;idx_s3_objects_bucket_prefix&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;s3_objects&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;bucket&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;key&lt;/span&gt; &lt;span class="n"&gt;text_pattern_ops&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;CREATE&lt;/span&gt; &lt;span class="k"&gt;INDEX&lt;/span&gt; &lt;span class="n"&gt;idx_s3_objects_tags&lt;/span&gt; &lt;span class="k"&gt;ON&lt;/span&gt; &lt;span class="n"&gt;s3_objects&lt;/span&gt; &lt;span class="k"&gt;USING&lt;/span&gt; &lt;span class="n"&gt;GIN&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tags&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sync the table on every &lt;code&gt;PutObject&lt;/code&gt; / &lt;code&gt;DeleteObject&lt;/code&gt; via S3 event notifications or application hooks. Query metadata directly from the database, and only use S3 API to read/write actual files.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Tradeoff:&lt;/strong&gt; You operate another database. &lt;strong&gt;Win:&lt;/strong&gt; metadata lookup latency stays consistent no matter how many objects you store.&lt;/p&gt;

&lt;h3&gt;
  
  
  Strategy 5: Pick storage built for your expected scale
&lt;/h3&gt;

&lt;p&gt;If you know you'll grow past 100M objects, evaluate systems based on their metadata architecture.&lt;/p&gt;

&lt;p&gt;Good questions to ask vendors:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;What's p99 ListObjectsV2 latency on a 100M-object bucket with a selective prefix?&lt;/li&gt;
&lt;li&gt;Does metadata run in-process, or rely on an external coordination service?&lt;/li&gt;
&lt;li&gt;How does LIST performance hold up during rebalancing or recovery?&lt;/li&gt;
&lt;li&gt;Can I read metadata without going through the standard S3 API?&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;RustFS metadata overview:&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Every node hosts embedded RocksDB for metadata. Clusters shard metadata by object key hash:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Single node:&lt;/strong&gt; Subsecond LIST responses for 100M+ objects with selective prefixes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Clustered:&lt;/strong&gt; Metadata split evenly across nodes&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Recovery:&lt;/strong&gt; Metadata replicates alongside object data; LIST stays available (minor staleness possible)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Offline option:&lt;/strong&gt; Export metadata snapshots to SQLite for analytics&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  When native S3 metadata stops fitting your workload
&lt;/h2&gt;

&lt;p&gt;Once you hit ~1B objects and need complex filtering, vanilla object storage isn't ideal for metadata-heavy workflows.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Symptom&lt;/th&gt;
&lt;th&gt;Fix&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Constant LIST timeouts&lt;/td&gt;
&lt;td&gt;Deploy external metadata index (Strategy 4)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complex filters (size limits, tag matching)&lt;/td&gt;
&lt;td&gt;Data lake formats (Iceberg / Delta Lake) or dedicated metadata DB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Full-text search over object names&lt;/td&gt;
&lt;td&gt;Add Elasticsearch / OpenSearch sidecar&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Relational-style joins on object metadata&lt;/td&gt;
&lt;td&gt;Move metadata out of S3 into a relational database&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;S3 shines when you fetch objects by known keys. It was never designed as a flexible query engine for object metadata.&lt;/p&gt;

&lt;h2&gt;
  
  
  TL;DR
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;Every S3-compatible storage hits a metadata scaling limit. Find your threshold before production hits it.&lt;/li&gt;
&lt;li&gt;Split data across multiple buckets — this gives you the biggest performance return.&lt;/li&gt;
&lt;li&gt;Build hierarchical object keys to make prefix filtering effective.&lt;/li&gt;
&lt;li&gt;Never run full-bucket scans in production; always use prefix filters + pagination.&lt;/li&gt;
&lt;li&gt;Around 100M objects, plan an event-driven external metadata store (PostgreSQL or SQLite).&lt;/li&gt;
&lt;li&gt;If you expect massive scale, prioritize metadata architecture during storage selection. RustFS (RocksDB-backed) and AWS S3 handle billions of objects better than etcd-dependent stacks.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Tired of slow LIST calls with millions of stored objects? RustFS uses RocksDB-backed metadata to deliver subsecond listings even at 100M+ objects. &lt;a href="https://rustfs.com/download" rel="noopener noreferrer"&gt;Download RustFS&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Is there a hard maximum number of objects per bucket?
&lt;/h3&gt;

&lt;p&gt;Theoretically no. AWS says buckets support virtually unlimited objects. Practically, your limit comes from metadata index speed.&lt;/p&gt;

&lt;p&gt;Most teams notice LIST slowdowns between 10M–50M objects, depending on key layout and access patterns. With clean partitioning and prefix design, 100M+ objects work fine. Once you near 1B objects, build an external metadata index regardless of storage platform.&lt;/p&gt;

&lt;h3&gt;
  
  
  Why do ListObjects requests slow down as object counts grow?
&lt;/h3&gt;

&lt;p&gt;ListObjects scans matching metadata entries, sorts keys lexicographically, and paginates results. Sorting creates heavy O(N log N) overhead when thousands or millions of entries match your prefix.&lt;/p&gt;

&lt;p&gt;Worse: most clients loop pagination, turning one logical job into dozens of API round-trips stacked with network latency.&lt;/p&gt;

&lt;p&gt;Fixes: tighter prefix filters, bucket partitioning, or offloading metadata queries to an external database.&lt;/p&gt;

&lt;h3&gt;
  
  
  Does bucket naming affect S3 performance?
&lt;/h3&gt;

&lt;p&gt;Generally not. Bucket names are routing and namespace identifiers, not performance controls. Operationally, stuffing all data into a small number of giant buckets concentrates metadata pressure and slows LIST. Spreading load across more buckets distributes pressure. AWS explicitly confirms bucket naming does not impact performance.&lt;/p&gt;

&lt;p&gt;The same applies to self-hosted systems like MinIO and RustFS. Bucket-level metadata overhead is negligible. Spend tuning time on key structure and partitioning instead.&lt;/p&gt;

&lt;h3&gt;
  
  
  What's the standard way to track S3 metadata externally?
&lt;/h3&gt;

&lt;p&gt;The common pattern: PostgreSQL (or MySQL) with &lt;code&gt;(bucket, object_key)&lt;/code&gt; as the primary key.&lt;/p&gt;

&lt;p&gt;Sync updates via S3 event notifications (SQS/SNS/Lambda on AWS; webhooks for self-hosted storage) on object creates, copies, and deletes. Query metadata directly from the database and reserve S3 API purely for file reads and writes.&lt;/p&gt;

&lt;p&gt;For lighter workloads with tens of millions of rows, SQLite works well. If you need search, pair the relational database with Elasticsearch or OpenSearch. The downside is another system to maintain; the upside is stable metadata query performance independent of bucket size.&lt;/p&gt;

&lt;h3&gt;
  
  
  Can I replace LIST with S3 Select for metadata filtering?
&lt;/h3&gt;

&lt;p&gt;No. S3 Select runs SQL inside object payloads (CSV, JSON, Parquet). It cannot filter on object-level attributes: names, sizes, tags, timestamps.&lt;/p&gt;

&lt;p&gt;Metadata filtering still requires either ListObjectsV2 (with scaling limits) or an external index. S3 Select solves a separate problem: scanning file contents without full downloads. Both tools are useful, but they cannot replace each other.&lt;/p&gt;

</description>
      <category>s3</category>
      <category>metadata</category>
      <category>objectstorage</category>
      <category>scalability</category>
    </item>
    <item>
      <title>Distributed Storage 101: How It Works and When You Actually Need It</title>
      <dc:creator>Ethan Carter</dc:creator>
      <pubDate>Sun, 09 Aug 2026 11:39:00 +0000</pubDate>
      <link>https://dev.to/ethan-carter/distributed-storage-101-how-it-works-and-when-you-actually-need-it-2a19</link>
      <guid>https://dev.to/ethan-carter/distributed-storage-101-how-it-works-and-when-you-actually-need-it-2a19</guid>
      <description>&lt;p&gt;Distributed storage isn't magic — it's a set of trade-offs. Here's how it actually works under the hood.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Stats&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Figure&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Orgs running distributed storage (mid-size+)&lt;/td&gt;
&lt;td&gt;~68%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Primary driver: HA/failure tolerance&lt;/td&gt;
&lt;td&gt;74%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Single-node disk failure recovery time&lt;/td&gt;
&lt;td&gt;2–8 hours&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Teams that regretted distributing too early&lt;/td&gt;
&lt;td&gt;~23%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What Makes Storage "Distributed"
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Single-node:&lt;/strong&gt; One process, one machine. If it dies → outage.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Distributed:&lt;/strong&gt; Data spread across multiple nodes. Individual failures don't cause data loss or downtime.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Single Node:   App → [Server + Disk] → if dies → GONE
Distributed:   App → [Node A] [Node B] [Node C] → if A dies → B+C serve
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  The Three Problems It Solves
&lt;/h2&gt;

&lt;h3&gt;
  
  
  1. Availability
&lt;/h3&gt;

&lt;p&gt;Hardware fails. Distributed systems survive individual component failures:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Failure Type&lt;/th&gt;
&lt;th&gt;Single-Node&lt;/th&gt;
&lt;th&gt;Distributed (3+ nodes)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Disk crash&lt;/td&gt;
&lt;td&gt;Outage&lt;/td&gt;
&lt;td&gt;Auto-rebalance, zero downtime&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Machine crash&lt;/td&gt;
&lt;td&gt;Outage&lt;/td&gt;
&lt;td&gt;Other nodes take over&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Rack power loss&lt;/td&gt;
&lt;td&gt;Outage&lt;/td&gt;
&lt;td&gt;If cross-rack → degraded but alive&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Rule:&lt;/strong&gt; &amp;gt;99.9% uptime SLA? Distributed gets you there by design.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Scale Beyond One Box
&lt;/h3&gt;

&lt;p&gt;One machine has limits (~500TB raw in a big chassis). Need 1 PB+? Add nodes.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Geographic Distribution
&lt;/h3&gt;

&lt;p&gt;Multi-region for compliance, latency, DR:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;US-East (Nodes 1-4)  ← primary
EU-West (Nodes 5-7)   ← compliance + EU users
APAC   (Nodes 8-10)   ← Asia + DR target
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  How Data Gets Placed: Consistent Hashing
&lt;/h2&gt;

&lt;p&gt;Most systems (RustFS, Ceph, Cassandra) use consistent hashing:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Hash the object key → big integer&lt;/li&gt;
&lt;li&gt;Map to position on a hash ring (circle of values)&lt;/li&gt;
&lt;li&gt;Each node owns a range of the ring&lt;/li&gt;
&lt;li&gt;Object stored on node(s) whose range contains its hash&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;strong&gt;Why not &lt;code&gt;hash % num_nodes&lt;/code&gt;?&lt;/strong&gt; Adding/removing a node with consistent hashing moves only ~1/N of data. Mod-N reshuffles everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  Replication vs. Erasure Coding
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Replication (Simple, Space-Heavy)
&lt;/h3&gt;

&lt;p&gt;Store N complete copies on different nodes.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;3× replication:&lt;/strong&gt; 200% space overhead, tolerate 2 failures, fast reads&lt;/li&gt;
&lt;li&gt;Best for: hot data, frequent reads&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Erasure Coding (Complex, Space-Efficient)
&lt;/h3&gt;

&lt;p&gt;Split data into fragments + compute parity.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;4+2 scheme:&lt;/strong&gt; 50% overhead, tolerate 2 failures, slower recovery&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;8+3 scheme:&lt;/strong&gt; 37.5% overhead, tolerate 3 failures&lt;/li&gt;
&lt;li&gt;Best for: warm/cold data, capacity-sensitive workloads&lt;/li&gt;
&lt;/ul&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Factor&lt;/th&gt;
&lt;th&gt;3× Replication&lt;/th&gt;
&lt;th&gt;4+2 EC&lt;/th&gt;
&lt;th&gt;8+3 EC&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Space overhead&lt;/td&gt;
&lt;td&gt;200%&lt;/td&gt;
&lt;td&gt;50%&lt;/td&gt;
&lt;td&gt;37.5%&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Failures tolerated&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;2&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Read speed&lt;/td&gt;
&lt;td&gt;Excellent&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;OK&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Write speed&lt;/td&gt;
&lt;td&gt;Good&lt;/td&gt;
&lt;td&gt;Moderate&lt;/td&gt;
&lt;td&gt;Slower&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Most production systems use both: replicate hot data, erasure-code cold.&lt;/p&gt;

&lt;h2&gt;
  
  
  Consistency Models
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Strong Consistency (CP)
&lt;/h3&gt;

&lt;p&gt;Every read returns the most recent write. Always.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Cost:&lt;/strong&gt; Higher latency during writes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Used by:&lt;/strong&gt; RustFS (default), Ceph, financial systems.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Eventual Consistency (AP)
&lt;/h3&gt;

&lt;p&gt;Writes acknowledged immediately; reads &lt;em&gt;might&lt;/em&gt; be briefly stale.&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Benefit:&lt;/strong&gt; Lower write latency, higher availability.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Used by:&lt;/strong&gt; S3 (cross-region), Cassandra, DynamoDB.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Acceptable for:&lt;/strong&gt; Content delivery, analytics, logs.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Practical reality:&lt;/strong&gt; Most systems are strong-consistency within a DC, eventual across regions.&lt;/p&gt;

&lt;h2&gt;
  
  
  CAP Theorem Explained
&lt;/h2&gt;

&lt;p&gt;CAP = Consistency + Availability + Partition tolerance. Pick two.&lt;/p&gt;

&lt;p&gt;But P is &lt;strong&gt;not optional&lt;/strong&gt; — networks partition. Real choice:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;CP&lt;/th&gt;
&lt;th&gt;AP&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;During network split&lt;/td&gt;
&lt;td&gt;Stop writes to avoid divergence&lt;/td&gt;
&lt;td&gt;Accept writes, reconcile later&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data safety&lt;/td&gt;
&lt;td&gt;✅ No corruption&lt;/td&gt;
&lt;td&gt;⚠️ Possible conflicts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Uptime&lt;/td&gt;
&lt;td&gt;⚠️ Partially unavailable&lt;/td&gt;
&lt;td&gt;✅ Fully available&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Examples&lt;/td&gt;
&lt;td&gt;RustFS, Ceph, MongoDB&lt;/td&gt;
&lt;td&gt;Cassandra, DynamoDB, S3 x-repl&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Most object storage is CP&lt;/strong&gt; — divergent data is worse than brief unavailability.&lt;/p&gt;

&lt;h2&gt;
  
  
  When You DON'T Need Distributed Storage
&lt;/h2&gt;

&lt;p&gt;Real costs to consider:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;th&gt;Reality&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Complexity&lt;/td&gt;
&lt;td&gt;Monitoring 3–15 nodes vs 1&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Latency&lt;/td&gt;
&lt;td&gt;Network round-trips vs local disk&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Overhead&lt;/td&gt;
&lt;td&gt;Metadata services consume CPU/RAM&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Learning curve&lt;/td&gt;
&lt;td&gt;3–6 months to proficiency&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Debugging&lt;/td&gt;
&lt;td&gt;More moving parts = harder troubleshooting&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Stay single-node when:&lt;/strong&gt; &amp;lt;10TB, downtime acceptable, no ops team, dev/homelab, budget tight.&lt;/p&gt;

&lt;p&gt;RustFS, MinIO, SeaweedFS all run great as single-node. Distribute when you hit a concrete wall.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Distributed Storage Breaks
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Split-brain:&lt;/strong&gt; Both sides of a partition accept writes → divergent data. CP systems refuse minority-side writes; AP systems hope for the best.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Rebalancing storms:&lt;/strong&gt; Adding a node triggers data migration that can degrade performance. Schedule during low traffic.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Slow node problem:&lt;/strong&gt; One slow node gets more retries → more load → slower. Thundering herd cascade.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multi-node failure:&lt;/strong&gt; Losing 3 nodes simultaneously (rack failure) may require human intervention.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Monitoring complexity:&lt;/strong&gt; "Is the cluster healthy?" has 6+ dimensions, not a yes/no answer.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  From Single Node to Cluster: Progressive Phases
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Phase 1: Single Node &lt;span class="o"&gt;(&lt;/span&gt;now&lt;span class="o"&gt;)&lt;/span&gt; — official &lt;span class="nb"&gt;command&lt;/span&gt;, sourced verbatim from RustFS GitHub README &lt;span class="o"&gt;[&lt;/span&gt;NOT EXECUTED IN CI]
  docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 9000:9000 &lt;span class="nt"&gt;-p&lt;/span&gt; 9001:9001 &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/data:/data &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/logs:/logs rustfs/rustfs:latest

Phase 2: Replicated Cluster &lt;span class="o"&gt;(&lt;/span&gt;need HA&lt;span class="o"&gt;)&lt;/span&gt;
  Add &lt;span class="nt"&gt;--cluster-nodes&lt;/span&gt; flag, deploy on 3 machines

Phase 3: Erasure-Coded Cluster &lt;span class="o"&gt;(&lt;/span&gt;need efficiency&lt;span class="o"&gt;)&lt;/span&gt;
  Configure ec.scheme&lt;span class="o"&gt;=&lt;/span&gt;4+2 &lt;span class="o"&gt;(&lt;/span&gt;needs 6+ drives&lt;span class="o"&gt;)&lt;/span&gt;

Phase 4: Multi-Region &lt;span class="o"&gt;(&lt;/span&gt;need geo-redundancy&lt;span class="o"&gt;)&lt;/span&gt;
  Add remote nodes, configure async replication rules
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Don't skip phases. Teams jumping from Phase 1→4 usually spend the next quarter debugging.&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom Line
&lt;/h2&gt;

&lt;p&gt;Distributed storage solves real problems at the cost of real complexity. The right move for most teams: &lt;strong&gt;start single-node, distribute when you hit a concrete wall.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;RustFS runs as a trivially simple single-node deploy and scales to clustered erasure-coded with the same binary — making it a strong "start here, stay here" option for teams leaving MinIO or outgrowing standalone setups.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What's the difference between distributed storage and just putting files on a server?&lt;/strong&gt;&lt;br&gt;
Single-server storage has a single point of failure. If that disk dies or that machine loses power, your data is gone until you restore from backup. Distributed storage spreads data across multiple nodes so individual failures don't cause data loss or downtime. The trade-off is operational complexity — you're now managing a cluster instead of a filesystem.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;When should I use distributed storage vs. single-node?&lt;/strong&gt;&lt;br&gt;
Use single-node (RustFS standalone, MinIO single-drive, SeaweedFS) for &amp;lt;10TB, non-critical workloads, homelabs, or development environments. Add distribution when you need high availability, capacity beyond one machine, throughput beyond one NIC/disk, or geographic redundancy. Don't distribute for distribution's sake — it adds latency, complexity, and operational overhead.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How does erasure coding work in simple terms?&lt;/strong&gt;&lt;br&gt;
Erasure coding splits data into N fragments, computes M parity fragments, and stores them across different drives/nodes. You can lose any M fragments and still reconstruct the data. A 4+2 scheme stores 4 data + 2 parity chunks across 6 locations; you lose any 2 and recover. Compared to 3x replication, 4+2 uses only 1.5x raw space while tolerating the same number of failures. The cost: reconstruction is CPU-intensive.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's CAP theorem and why does everyone argue about it?&lt;/strong&gt;&lt;br&gt;
CAP says a distributed system can guarantee at most two of three: Consistency, Availability, Partition tolerance. "P" isn't optional — networks do partition — so the real choice is CP (consistency over availability during a split) or AP (availability, accept temporary inconsistency). Most storage systems are CP because divergent data is worse than briefly unavailable data.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is RustFS distributed? How does it compare to Ceph?&lt;/strong&gt;&lt;br&gt;
RustFS supports both single-node and clustered deployment. In clustered mode it uses erasure coding with configurable schemes (default 4+2) and supports adding/removing nodes dynamically. Ceph is more mature for massive deployments (100+ nodes, petabyte-scale) with unified object/block/file storage via RADOS. RustFS is simpler to operate, has lower resource overhead (95MB idle vs Ceph's GB-range), and is written in Rust which eliminates a class of memory-safety bugs. For most teams under 50PB, RustFS hits the complexity/performance sweet spot.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Feedback? &lt;a href="https://github.com/rustfs/rustfs/issues" rel="noopener noreferrer"&gt;GitHub Issues&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

</description>
      <category>storage</category>
      <category>distributed</category>
      <category>ceph</category>
      <category>rustfs</category>
    </item>
    <item>
      <title>What Is Amazon S3, Really? (2026)</title>
      <dc:creator>Ethan Carter</dc:creator>
      <pubDate>Sun, 09 Aug 2026 10:53:00 +0000</pubDate>
      <link>https://dev.to/ethan-carter/what-is-amazon-s3-really-2026-4cle</link>
      <guid>https://dev.to/ethan-carter/what-is-amazon-s3-really-2026-4cle</guid>
      <description>&lt;h1&gt;
  
  
  What Is Amazon S3, Really? The 2026 Explanation
&lt;/h1&gt;

&lt;blockquote&gt;
&lt;p&gt;S3 launched in March 2006 — before the iPhone, before Airbnb, before "the cloud" was a household term.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  One Paragraph
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;S3 = flat key-value object store over HTTP.&lt;/strong&gt; You give it data + a key (&lt;code&gt;uploads/photo.jpg&lt;/code&gt;), it stores it redundantly. You request the key, it returns the data. Everything else — storage classes, encryption, replication — builds on that simple contract.&lt;/p&gt;

&lt;h2&gt;
  
  
  S3 vs Everything Else
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;vs File Systems&lt;/th&gt;
&lt;th&gt;vs Block Storage&lt;/th&gt;
&lt;th&gt;vs Databases&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Flat namespace (no real folders)&lt;/td&gt;
&lt;td&gt;API, not raw disk&lt;/td&gt;
&lt;td&gt;Opaque blobs, not structured records&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Eventually consistent for overwrites&lt;/td&gt;
&lt;td&gt;No seekable random access&lt;/td&gt;
&lt;td&gt;No query language&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Immutable objects&lt;/td&gt;
&lt;td&gt;Whole-object read/write&lt;/td&gt;
&lt;td&gt;Key-based access only&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Pricing: 4 Components
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Storage:&lt;/strong&gt; $0.023/GB/mo (Standard)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Requests:&lt;/strong&gt; $0.005/1K PUTs, $0.0004/1K GETs&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Egress:&lt;/strong&gt; $0.09/GB after 100GB free&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Data management:&lt;/strong&gt; Tags, analytics, replication&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;A busy 10TB bucket: ~&lt;strong&gt;$530/month&lt;/strong&gt; (storage + requests + egress).&lt;/p&gt;

&lt;h2&gt;
  
  
  Storage Class Ladder
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Class&lt;/th&gt;
&lt;th&gt;Cost&lt;/th&gt;
&lt;th&gt;When&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Standard&lt;/td&gt;
&lt;td&gt;$0.023/GB&lt;/td&gt;
&lt;td&gt;Hot data&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;IA&lt;/td&gt;
&lt;td&gt;$0.0125/GB&lt;/td&gt;
&lt;td&gt;Monthly access&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Glacier IR&lt;/td&gt;
&lt;td&gt;$0.004/GB&lt;/td&gt;
&lt;td&gt;Rare but fast retrieval&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Deep Archive&lt;/td&gt;
&lt;td&gt;$0.00099/GB&lt;/td&gt;
&lt;td&gt;"Delete never"&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Self-Hosted Alternatives
&lt;/h2&gt;

&lt;p&gt;MinIO, &lt;a href="https://rustfs.com" rel="noopener noreferrer"&gt;RustFS&lt;/a&gt;, Ceph RGW all implement S3 API. Same &lt;code&gt;s3://&lt;/code&gt; URIs, zero egress/request fees on your own hardware.&lt;/p&gt;




&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What does S3 stand for?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Simple Storage Service. Despite the name, there's nothing particularly "simple" about the full feature set anymore — it started simple in 2006 and accumulated capabilities (storage classes, replication, encryption, analytics) over 20 years. But the core contract remains elegantly simple: give me bytes + a key, I'll store them. Give me the key back, I'll return the bytes.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is S3 a file system?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. S3 is an object store with a flat key namespace. The &lt;code&gt;/&lt;/code&gt; characters in keys look like directory separators but aren't — S3 has no real folders, no hierarchical structure, and no POSIX semantics (no hard links, symlinks, permissions, or in-place modification). Tools like &lt;code&gt;aws s3 sync&lt;/code&gt; and s3fs present a filesystem-like interface on top of S3, but underneath it's still a key-value store.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How much does S3 really cost?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It depends on your usage pattern, but a typical production workload has 4 cost components: (1) Storage: $0.023/GB/month for Standard, (2) Requests: $0.005 per 1,000 PUTs, $0.0004 per 1,000 GETs, (3) Egress: $0.09/GB after the first 100GB free tier, (4) Data management: tags, analytics, replication. For a 10TB bucket with moderate activity (1M GETs/day, 2TB egress/month), expect $230 storage + $120 requests + $180 egress = ~$530/month. Self-hosted S3 alternatives eliminate components 2-4 entirely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I run my own S3-compatible server?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes. Multiple open-source projects implement the S3 API: MinIO (Go, largest community), RustFS (Rust, focused on performance), Ceph RGW (C++, part of Ceph platform), SeaweedFS (Go, simpler architecture). All support the core S3 operations (PutObject, GetObject, ListObjects, Multipart Upload) and can be dropped in as replacements for AWS S3 in most applications by changing the endpoint URL. See our bare metal deployment guide for details.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What is the maximum file size in S3?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;5 TB per object. For files larger than 5 GB, you must use Multipart Upload, which splits the file into parts (5 MB to 5 GB each, up to 10,000 parts). This is handled automatically by AWS SDKs, the AWS CLI, and most S3 clients — your application code typically doesn't need to change. The 5 TB single-object limit has existed since S3's launch and hasn't changed.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;&lt;a href="https://rustfs.com" rel="noopener noreferrer"&gt;RustFS&lt;/a&gt; — S3-compatible storage without the AWS bill. &lt;a href="https://rustfs.com/download" rel="noopener noreferrer"&gt;Download&lt;/a&gt;.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>aws</category>
      <category>s3</category>
      <category>storage</category>
      <category>explained</category>
    </item>
    <item>
      <title>FINRA-Compliant Storage with S3 Object Lock: A Practical Guide for 2026</title>
      <dc:creator>Ethan Carter</dc:creator>
      <pubDate>Fri, 07 Aug 2026 11:26:00 +0000</pubDate>
      <link>https://dev.to/ethan-carter/finra-compliant-storage-with-s3-object-lock-a-practical-guide-for-2026-53m1</link>
      <guid>https://dev.to/ethan-carter/finra-compliant-storage-with-s3-object-lock-a-practical-guide-for-2026-53m1</guid>
      <description>&lt;p&gt;FINRA Rule 17a-4(f) requires WORM storage. Here's how S3 Object Lock satisfies it on self-hosted infrastructure — with implementation examples and a comparison of which systems actually support compliance-mode locking.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Stats&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Figure&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;FINRA enforcement actions citing recordkeeping (2025)&lt;/td&gt;
&lt;td&gt;~340&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Avg fine per firm for recordkeeping deficiencies&lt;/td&gt;
&lt;td&gt;$225K&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Firms using cloud WORM storage for 17a-4(f)&lt;/td&gt;
&lt;td&gt;~73%&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What FINRA Actually Requires
&lt;/h2&gt;

&lt;p&gt;Three rules matter:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;SEC Rule 17a-4(f)&lt;/strong&gt; — Electronic records must be stored in either:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Option A (WORM):&lt;/strong&gt; Non-rewriteable, non-erasable format — no one can modify or delete records until retention expires.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Option B (Audit Trail):&lt;/strong&gt; Complete time-stamped audit trail of every modification/deletion.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Option A is easier to defend in exams because the technology prevents tampering. Option A's digital standard: &lt;strong&gt;S3 Object Lock in Compliance mode.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FINRA Rule 4511(c)&lt;/strong&gt; — Records must be indexed, accessible (first 2 years immediately), and reproducible.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;FINRA Rule 3110&lt;/strong&gt; — Supervisory controls preventing unauthorized modification.&lt;/p&gt;

&lt;h2&gt;
  
  
  Compliance Mode vs. Governance Mode
&lt;/h2&gt;

&lt;p&gt;This is the critical distinction:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Compliance Mode:   locked → NO ONE can delete → ✅ FINRA OK
Governance Mode:  locked → root CAN bypass    → ⚠️ Need extra controls
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For FINRA examination purposes, &lt;strong&gt;Compliance mode is the standard answer.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Which Systems Support Object Lock
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;System&lt;/th&gt;
&lt;th&gt;Object Lock&lt;/th&gt;
&lt;th&gt;Compliance Mode&lt;/th&gt;
&lt;th&gt;Legal Hold&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;AWS S3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RustFS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅ (v1.2+)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MinIO&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ceph RGW&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;Limited&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Wasabi&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SeaweedFS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Garage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;SeaweedFS and Garage don't implement Object Lock at all. If you're using them for regulated data, you'll need an external WORM layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Implementation: Step by Step
&lt;/h2&gt;

&lt;p&gt;Using RustFS as the S3-compatible backend (same pattern applies to any compliant system):&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 1: Enable Object Lock at Bucket Creation
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws &lt;span class="nt"&gt;--endpoint-url&lt;/span&gt; http://localhost:9000 s3api create-bucket &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--bucket&lt;/span&gt; finra-compliance-records &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--object-lock-enabled-for-bucket&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Object Lock must be enabled at creation — can't be added to existing buckets.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Set Default Retention (6 years)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;aws &lt;span class="nt"&gt;--endpoint-url&lt;/span&gt; http://localhost:9000 s3api put-object-lock-configuration &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--bucket&lt;/span&gt; finra-compliance-records &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--object-lock-configuration&lt;/span&gt; &lt;span class="s1"&gt;'{
    "ObjectLockEnabled": "Enabled",
    "Rule": {
      "DefaultRetention": {
        "Mode": "COMPLIANCE",
        "Days": 2200
      }
    }
  }'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 3: Upload with Retention
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;
&lt;span class="kn"&gt;from&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt; &lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;datetime&lt;/span&gt;

&lt;span class="n"&gt;s3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s3&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;endpoint_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;http://localhost:9000&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;aws_access_key_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;your-key&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;aws_secret_access_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;your-secret&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c1"&gt;# Trade record: 6-year retention
&lt;/span&gt;&lt;span class="n"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;Bucket&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;finra-compliance-records&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;trades/2026/07/T123456.json&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;T123456.json&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
    &lt;span class="n"&gt;ObjectLockMode&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;COMPLIANCE&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;ObjectLockRetainUntilDate&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;datetime&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;2032&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;7&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="mi"&gt;24&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 4: Verify Immutability (Critical!)
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Try deleting a locked object — should FAIL with 403 AccessDenied&lt;/span&gt;
aws &lt;span class="nt"&gt;--endpoint-url&lt;/span&gt; http://localhost:9000 s3api delete-object &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--bucket&lt;/span&gt; finra-compliance-records &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--key&lt;/span&gt; trades/2026/07/T123456.json

&lt;span class="c"&gt;# Error: "The object is locked with COMPLIANCE mode retention..."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Document this test.&lt;/strong&gt; Screenshot the error. Keep it for examiners.&lt;/p&gt;

&lt;h2&gt;
  
  
  Retention Strategy by Record Type
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Record Type&lt;/th&gt;
&lt;th&gt;Retention&lt;/th&gt;
&lt;th&gt;Days&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Trade confirmations &amp;amp; order tickets&lt;/td&gt;
&lt;td&gt;6 years&lt;/td&gt;
&lt;td&gt;2200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Customer account records&lt;/td&gt;
&lt;td&gt;6 yrs post-closure&lt;/td&gt;
&lt;td&gt;2300&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Customer communications&lt;/td&gt;
&lt;td&gt;3 years&lt;/td&gt;
&lt;td&gt;1100&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Blotters &amp;amp; ledgers&lt;/td&gt;
&lt;td&gt;6 years&lt;/td&gt;
&lt;td&gt;2200&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Complaint records&lt;/td&gt;
&lt;td&gt;4+ years&lt;/td&gt;
&lt;td&gt;1500+legal hold&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Marketing materials (RIAs)&lt;/td&gt;
&lt;td&gt;5 years&lt;/td&gt;
&lt;td&gt;1850&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Create separate buckets per retention tier — simplifies auditing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Self-Hosted vs. Cloud for FINRA Workloads
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Factor&lt;/th&gt;
&lt;th&gt;Self-Hosted (RustFS)&lt;/th&gt;
&lt;th&gt;Cloud (AWS/Wasabi)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;WORM capability&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Examiner familiarity&lt;/td&gt;
&lt;td&gt;⚠️ Needs explanation&lt;/td&gt;
&lt;td&gt;✅ Ends questions&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cost at 100TB+&lt;/td&gt;
&lt;td&gt;✅ 3–5x cheaper&lt;/td&gt;
&lt;td&gt;💰 Egress adds up&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Data sovereignty&lt;/td&gt;
&lt;td&gt;✅ You control it&lt;/td&gt;
&lt;td&gt;⚠️ Region-dependent&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;D3P ecosystem&lt;/td&gt;
&lt;td&gt;Less common&lt;/td&gt;
&lt;td&gt;Well-established&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Self-hosting wins&lt;/strong&gt; when you have 50TB+, existing ops capacity, or data residency needs. &lt;strong&gt;Cloud wins&lt;/strong&gt; for smaller firms prioritizing examiner familiarity.&lt;/p&gt;

&lt;h2&gt;
  
  
  Where Self-Hosted Gets Tricky
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;D3P designation&lt;/strong&gt; is harder with self-hosted infra (cloud has established ecosystems)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Examiner skepticism&lt;/strong&gt; — be ready with documentation, test results, config screenshots&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Version upgrades&lt;/strong&gt; need regression tests against WORM guarantees&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DR replica&lt;/strong&gt; must also enforce Object Lock (compliance gap if it doesn't)&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None are deal-breakers — just budget engineering time accordingly.&lt;/p&gt;

&lt;h2&gt;
  
  
  Pre-Exam Checklist
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Object Lock enabled on all compliance buckets (at creation)&lt;/li&gt;
&lt;li&gt;[ ] Default retention = &lt;strong&gt;Compliance&lt;/strong&gt; mode (not Governance)&lt;/li&gt;
&lt;li&gt;[ ] Retention periods match record-type requirements&lt;/li&gt;
&lt;li&gt;[ ] Legal hold mechanism tested and documented&lt;/li&gt;
&lt;li&gt;[ ] Failed delete attempts documented (screenshots!)&lt;/li&gt;
&lt;li&gt;[ ] DR replica also enforces Object Lock&lt;/li&gt;
&lt;li&gt;[ ] WSPs reference storage architecture&lt;/li&gt;
&lt;li&gt;[ ] D3P designation filed&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Bottom Line
&lt;/h2&gt;

&lt;p&gt;FINRA doesn't care if your WORM storage runs on AWS or your own RustFS cluster. What matters: &lt;strong&gt;can you prove tamper-proof retention, produce records fast, and demonstrate it to an examiner?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;S3 Object Lock in Compliance mode is the clearest path because the technology makes violations impossible — not just against policy. For self-hosted teams, &lt;strong&gt;RustFS&lt;/strong&gt; offers full Object Lock parity with AWS S3. Verify your version, test adversarially, document everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Does FINRA require cloud storage, or can I self-host?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;FINRA does not mandate cloud storage. What it mandates (via SEC Rule 17a-4(f)) is that electronic records be stored in a non-rewriteable, non-erasable format — WORM — for the applicable retention period. If your self-hosted S3-compatible system implements Object Lock in Compliance mode with tamper-proof retention, it can satisfy the WORM requirement. The key is whether your storage system's immutability controls meet the regulatory standard, not who hosts the servers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What's the difference between Governance mode and Compliance mode for Object Lock?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Governance mode allows users with special IAM permissions (like &lt;code&gt;s3:BypassGovernanceRetention&lt;/code&gt;) to overwrite or delete an object before retention expires. Compliance mode does not — no user, not even root or account admin, can delete or overwrite a locked object until retention expires. For FINRA Rule 17a-4(f) compliance, you need Compliance mode. Governance mode is useful for internal data governance but doesn't satisfy regulatory WORM requirements.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How long do I need to retain records under FINRA rules?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It depends on the record type. Most customer communications and trade records require 3–6 years. Customer account records need 6 years after account closure. Blotters and ledgers typically require 6 years. Complaint records need at least 4 years (often longer if litigation risk exists). The first 2 years must be "easily accessible" — meaning regulators can get them quickly without special procedures. Years 3+ can be on slower/colder storage but still retrievable on request.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can RustFS or MinIO handle FINRA-grade Object Lock?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;RustFS supports S3 Object Lock in both Governance and Compliance modes as of v1.2+. MinIO also supports Object Lock. Both implement the same S3 API (&lt;code&gt;put-object-retention&lt;/code&gt;, &lt;code&gt;get-object-retention&lt;/code&gt;, &lt;code&gt;put-object-legal-hold&lt;/code&gt;). For production FINRA workloads, verify your specific version supports the full Object Lock API surface, test retention enforcement with an adversarial attempt (try deleting a locked object as root), and document the configuration for your examiner.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What happens during a FINRA exam if my storage doesn't support Object Lock?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;FINRA examiners evaluate whether your storage architecture satisfies SEC Rule 17a-4(f)'s immutability requirement. If you're using standard (non-WORM) object storage, you'll need to demonstrate an alternative compliant approach — such as a complete audit trail system that logs every modification/deletion with timestamps and identities (the "audit trail alternative" added in the October 2022 rule amendments). This is harder to defend in an exam than true WORM storage because you're proving a process works rather than demonstrating that the technology makes violations impossible.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;Not legal advice. Consult qualified securities counsel. Last updated: July 2026.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>finra</category>
      <category>compliance</category>
      <category>s3</category>
      <category>rustfs</category>
    </item>
    <item>
      <title>S3-Compatible Storage Explained: The De Facto Standard for Object Storage in 2026</title>
      <dc:creator>Ethan Carter</dc:creator>
      <pubDate>Wed, 05 Aug 2026 11:18:00 +0000</pubDate>
      <link>https://dev.to/ethan-carter/s3-compatible-storage-explained-the-de-facto-standard-for-object-storage-in-2026-2h4a</link>
      <guid>https://dev.to/ethan-carter/s3-compatible-storage-explained-the-de-facto-standard-for-object-storage-in-2026-2h4a</guid>
      <description>&lt;p&gt;"S3-compatible" is one of those phrases that gets thrown around so much that people nod along without checking whether everyone means the same thing. Here's what it actually means, why it became the de facto standard, and what changes when you pick one implementation over another.&lt;/p&gt;

&lt;h2&gt;
  
  
  What "S3-Compatible" Actually Means
&lt;/h2&gt;

&lt;p&gt;S3 compatibility means implementing &lt;strong&gt;Amazon's S3 REST API&lt;/strong&gt; as a protocol — not as an AWS service you pay for. Specifically, it means supporting:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The shared data model:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bucket&lt;/strong&gt; — A flat namespace container (&lt;code&gt;user-uploads&lt;/code&gt;, &lt;code&gt;backups&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Object&lt;/strong&gt; — Key-value pair inside a bucket (&lt;code&gt;backups/2026-07-24.db.gz&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Key&lt;/strong&gt; — Unique identifier for each object&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Access Key / Secret Key&lt;/strong&gt; — Credential pair for auth&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;The core operations (what "compatible" guarantees):&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;PUT    /bucket/key          → Upload
GET    /bucket/key          → Download
DELETE /bucket/key          → Remove
HEAD   /bucket/key          → Check existence + metadata
LIST   /bucket?prefix=      → Enumerate objects
PUT    /bucket              → Create bucket
DELETE /bucket              → Remove empty bucket
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If a system implements these seven operations with Signature V4 auth, the AWS CLI, boto3, rclone, and most S3 SDKs work out of the box.&lt;/p&gt;

&lt;h2&gt;
  
  
  What It Does NOT Guarantee
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;AWS S3&lt;/th&gt;
&lt;th&gt;Typical Compatible System&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Infinite scalability&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Limited by your hardware&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;11 nines durability&lt;/td&gt;
&lt;td&gt;Claimed&lt;/td&gt;
&lt;td&gt;Varies by erasure coding config&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;200+ API endpoints&lt;/td&gt;
&lt;td&gt;Full spec&lt;/td&gt;
&lt;td&gt;Core 20–50 endpoints&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Glacier tiering&lt;/td&gt;
&lt;td&gt;Native&lt;/td&gt;
&lt;td&gt;Rarely implemented&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Event notifications (→ Lambda)&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Almost never&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;S3 compatibility is a spectrum, not a binary.&lt;/strong&gt; Core CRUD is reliable. Everything else needs per-implementation verification.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why S3 Won (And Not Swift, Or NFS)
&lt;/h2&gt;

&lt;p&gt;Four reasons:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;First-mover advantage.&lt;/strong&gt; AWS launched S3 in 2006 — years before OpenStack Swift (2012) or Ceph's mature S3 frontend. Thousands of apps hardcoded &lt;code&gt;boto3.client('s3')&lt;/code&gt; before competitors existed.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;SDK ecosystem moat.&lt;/strong&gt; Every language has an official AWS SDK. Using them against a compatible endpoint requires changing exactly two lines: &lt;code&gt;endpoint_url&lt;/code&gt; and &lt;code&gt;region&lt;/code&gt;.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Lock-in prevention became the selling point.&lt;/strong&gt; Ironically, Amazon's proprietary protocol became the anti-lock-in standard because it meant you could move between providers without touching application code.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;The MinIO effect.&lt;/strong&gt; From 2014–2025, MinIO proved high-fidelity S3 could run on commodity hardware. Even after their community-model shifts in late 2025, the installed base of S3-aware applications is so large that any new object storage project &lt;em&gt;not&lt;/em&gt; speaking S3 is a non-starter.&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;(Parallel with HTTP: Berners-Lee didn't design it to be universal transport — network effects made it one.)&lt;/p&gt;

&lt;h2&gt;
  
  
  Who Offers S3-Compatible Storage in 2026
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Cloud-Native (Pay Per Operation)
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Provider&lt;/th&gt;
&lt;th&gt;Price/GB/mo&lt;/th&gt;
&lt;th&gt;Egress&lt;/th&gt;
&lt;th&gt;Best For&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Amazon S3&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$0.023&lt;/td&gt;
&lt;td&gt;$0.09/GB&lt;/td&gt;
&lt;td&gt;Already in AWS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Wasabi&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$0.0069&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;$0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;S3 drop-in replacement&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Backblaze B2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;$0.006&lt;/td&gt;
&lt;td&gt;$0.01/GB&lt;/td&gt;
&lt;td&gt;Cheapest cloud DR target&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h3&gt;
  
  
  Self-Hosted Open Source
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Project&lt;/th&gt;
&lt;th&gt;License&lt;/th&gt;
&lt;th&gt;Lang&lt;/th&gt;
&lt;th&gt;Min Nodes&lt;/th&gt;
&lt;th&gt;Standout&lt;/th&gt;
&lt;th&gt;Weakness&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RustFS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Apache 2.0&lt;/td&gt;
&lt;td&gt;Rust&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Write throughput 2+× MinIO; 95MB idle memory&lt;/td&gt;
&lt;td&gt;Younger ecosystem&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MinIO&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AGPLv3&lt;/td&gt;
&lt;td&gt;Go&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Largest user base; richest feature parity&lt;/td&gt;
&lt;td&gt;Community edition in maintenance mode&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ceph (RGW)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;LGPLv2.1&lt;/td&gt;
&lt;td&gt;C++&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Unified storage; exabyte-proven&lt;/td&gt;
&lt;td&gt;Operational complexity&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SeaweedFS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Apache 2.0&lt;/td&gt;
&lt;td&gt;Go&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Lightweight; edge-friendly&lt;/td&gt;
&lt;td&gt;~60% S3 API coverage&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Garage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AGPLv3&lt;/td&gt;
&lt;td&gt;Rust&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Geo-distributed-first&lt;/td&gt;
&lt;td&gt;Small community&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  How to Choose: 5 Questions
&lt;/h2&gt;

&lt;p&gt;Don't start from products. Start from constraints:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;1. Are you staying in AWS?&lt;/strong&gt; Yes → stick with S3 unless egress costs are killing you. No → self-hosted becomes compelling immediately.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. What's your scale?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&amp;lt; 10 TB → &lt;strong&gt;RustFS or SeaweedFS&lt;/strong&gt; (single node)&lt;/li&gt;
&lt;li&gt;10–500 TB → &lt;strong&gt;RustFS or MinIO&lt;/strong&gt; (distributed)&lt;/li&gt;
&lt;li&gt;500 TB – 50 PB → &lt;strong&gt;Ceph RGW&lt;/strong&gt; (enterprise scale)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;3. License tolerance?&lt;/strong&gt; Embedding in closed-source product → avoid AGPLv3. Zero licensing anxiety → Apache 2.0 only (RustFS, SeaweedFS).&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;4. Workload pattern?&lt;/strong&gt; Sequential large writes → &lt;strong&gt;RustFS&lt;/strong&gt;. Mixed random I/O → &lt;strong&gt;MinIO or Ceph&lt;/strong&gt;. Edge/IoT → &lt;strong&gt;SeaweedFS&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;5. Who operates it?&lt;/strong&gt; Solo dev → lightweight option. Dedicated SRE team → &lt;strong&gt;Ceph&lt;/strong&gt;. Want managed → &lt;strong&gt;Wasabi/B2&lt;/strong&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It Yourself (RustFS Example)
&lt;/h2&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Single-node Docker deploy (official command — sourced from https://github.com/rustfs/rustfs README, NOT EXECUTED IN CI)&lt;/span&gt;
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 9000:9000 &lt;span class="nt"&gt;-p&lt;/span&gt; 9001:9001 &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/data:/data &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/logs:/logs rustfs/rustfs:latest

&lt;span class="c"&gt;# AWS CLI — only endpoint URL changes&lt;/span&gt;
aws &lt;span class="nt"&gt;--endpoint-url&lt;/span&gt; http://localhost:9000 s3 mb s3://my-bucket
aws &lt;span class="nt"&gt;--endpoint-url&lt;/span&gt; http://localhost:9000 s3 &lt;span class="nb"&gt;cp &lt;/span&gt;README.md s3://my-bucket/
aws &lt;span class="nt"&gt;--endpoint-url&lt;/span&gt; http://localhost:9000 s3 &lt;span class="nb"&gt;ls &lt;/span&gt;s3://my-bucket/
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Python code (identical to AWS S3 usage):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="kn"&gt;import&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;

&lt;span class="n"&gt;s3&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;boto3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;client&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;s3&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;endpoint_url&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;http://localhost:9000&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;  &lt;span class="c1"&gt;# ← Only this line differs
&lt;/span&gt;    &lt;span class="n"&gt;aws_access_key_id&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rustfsadmin&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="n"&gt;aws_secret_access_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rustfsadmin&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="n"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;create_bucket&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Bucket&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ml-datasets&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;s3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;put_object&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Bucket&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;ml-datasets&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;model.pt&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;Body&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nf"&gt;open&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;model.pt&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="s"&gt;rb&lt;/span&gt;&lt;span class="sh"&gt;'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Your code doesn't know or care whether it's talking to us-east-1 or localhost:9000. That's the whole point.&lt;/strong&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Where It Breaks Down (Production Gotchas)
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Response headers differ.&lt;/strong&gt; Apps parsing &lt;code&gt;x-amz-request-id&lt;/code&gt; will break on non-AWS systems.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Error codes aren't identical.&lt;/strong&gt; Catch on HTTP status code, not error string.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Multipart upload behavior varies.&lt;/strong&gt; Part size limits, abort-cleanup timing are implementation-defined.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Event notifications are mostly absent.&lt;/strong&gt; No self-hosted system fires S3 events to serverless functions natively.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Performance isn't portable.&lt;/strong&gt; P99 GET on local RustFS (~20ms LAN) vs AWS S3 (~100ms same region) vs geo-Ceph (~300ms).&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;None are deal-breakers for most teams — but know them before you go to production.&lt;/p&gt;

&lt;h2&gt;
  
  
  Feature Matrix Quick Reference
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;RustFS&lt;/th&gt;
&lt;th&gt;MinIO&lt;/th&gt;
&lt;th&gt;Ceph RGW&lt;/th&gt;
&lt;th&gt;SeaweedFS&lt;/th&gt;
&lt;th&gt;Wasabi&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Core CRUD&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Versioning&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;SSE (SSE-S3/SSE-C)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Object Lock&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Lifecycle policies&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Event notifications&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Single-node&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;N/A&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;License&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;Apache 2.0&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AGPLv3&lt;/td&gt;
&lt;td&gt;LGPLv2.1&lt;/td&gt;
&lt;td&gt;Apache 2.0&lt;/td&gt;
&lt;td&gt;Proprietary&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Accurate as of July 2026. Check official docs for latest status.&lt;/em&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Bottom Line
&lt;/h2&gt;

&lt;p&gt;S3 compatibility in 2026 is what SQL was to databases in the 1990s: &lt;strong&gt;the interface that survived because alternatives couldn't overcome switching costs of the installed base.&lt;/strong&gt; It's not perfect — but for 90% of teams, picking any S3-compatible system and moving on is the right call.&lt;/p&gt;

&lt;p&gt;The decision isn't &lt;em&gt;whether&lt;/em&gt; to use S3-compatible storage — it's &lt;strong&gt;which one&lt;/strong&gt;. And that comes down to license tolerance, scale, workload pattern, and who pages at 3 AM when a disk fails.&lt;/p&gt;

&lt;p&gt;For teams evaluating self-hosted object storage — especially those moving away from MinIO's community edition — &lt;strong&gt;RustFS&lt;/strong&gt; offers Apache 2.0 licensing, single-node-to-cluster scaling, and throughput leading the open-source field. Not right for every workload, but deserves a spot on your shortlist.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What does "S3-compatible" actually mean?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It means a storage system implements Amazon's Simple Storage Service (S3) REST API — the same bucket/object model, the same authentication (Signature V4), and the same core operations (PUT, GET, DELETE, List). If your code works with AWS S3, it works with any S3-compatible system after changing the endpoint URL and credentials. That's the whole point.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is S3 compatibility truly universal, or are there gaps?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Core operations (CRUD on objects, bucket lifecycle, presigned URLs) are nearly universal. But advanced features vary: Object Lock / legal hold is supported by MinIO, RustFS, and Wasabi but missing from SeaweedFS. Cross-region replication exists in Ceph RGW and cloud providers but not in most lightweight options. Always test your specific feature set against your target system's API docs before committing.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I use AWS CLI with S3-compatible storage?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes. Set &lt;code&gt;AWS_ENDPOINT_URL&lt;/code&gt; to your server's address and configure access keys. Example: &lt;code&gt;aws --endpoint-url http://localhost:9000 s3 ls&lt;/code&gt;. Most S3-compatible systems also work with rclone, Cyberduck, s3cmd, and language SDKs (boto3, aws-sdk-go, @aws-sdk/javascript) without modification.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which S3-compatible storage is fastest?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It depends entirely on the workload profile. For sequential large-object PUT throughput, RustFS leads at 2.1–2.3x over MinIO in our benchmarks (4 KiB – 10 MiB range). For small random GET operations, MinIO still holds an edge in mixed workloads. Cloud S3 has the lowest operational latency if you're already in AWS. Benchmark your own workload — published numbers reflect the tester's configuration, not yours.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Do I need to pay Amazon to use S3-compatible storage?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. S3 is an API protocol, not a service you buy from Amazon. Self-hosted S3-compatible systems like RustFS, Ceph, and SeaweedFS are free and open-source (check each project's license). You pay only for your own infrastructure — servers, disks, network. Cloud S3-compatible options like Wasabi and Backblaze B2 charge their own rates, independent of AWS.&lt;/p&gt;




&lt;p&gt;Feedback? &lt;a href="https://github.com/rustfs/rustfs/issues" rel="noopener noreferrer"&gt;GitHub Issues&lt;/a&gt; &lt;/p&gt;

</description>
      <category>s3</category>
      <category>aws</category>
      <category>storage</category>
      <category>rustfs</category>
    </item>
    <item>
      <title>Best MinIO Alternatives in 2026: 6 Options That Actually Work</title>
      <dc:creator>Ethan Carter</dc:creator>
      <pubDate>Tue, 04 Aug 2026 11:28:00 +0000</pubDate>
      <link>https://dev.to/ethan-carter/best-minio-alternatives-in-2026-6-options-that-actually-work-17p2</link>
      <guid>https://dev.to/ethan-carter/best-minio-alternatives-in-2026-6-options-that-actually-work-17p2</guid>
      <description>&lt;p&gt;The best MinIO alternative in 2026 isn't one product — it's whichever one matches your license tolerance, cluster size, and throughput profile. After MinIO shifted its community model in late 2025, teams evaluating self-hosted S3-compatible storage now cross-shop RustFS, Ceph, SeaweedFS, and Garage before committing. Below is a comparison grounded in what each project actually does well, where they struggle, and which workloads fit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Stats&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Alternative&lt;/th&gt;
&lt;th&gt;License&lt;/th&gt;
&lt;th&gt;Language&lt;/th&gt;
&lt;th&gt;Min Nodes&lt;/th&gt;
&lt;th&gt;Best Fit&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;RustFS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Apache 2.0&lt;/td&gt;
&lt;td&gt;Rust&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;High-throughput S3, write-heavy workloads&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Ceph (RGW)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;LGPLv2.1&lt;/td&gt;
&lt;td&gt;C++&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Enterprise unified (object + block + file)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;SeaweedFS&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Apache 2.0&lt;/td&gt;
&lt;td&gt;Go&lt;/td&gt;
&lt;td&gt;1&lt;/td&gt;
&lt;td&gt;Lightweight, small clusters, edge&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Garage&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AGPLv3&lt;/td&gt;
&lt;td&gt;Rust&lt;/td&gt;
&lt;td&gt;3&lt;/td&gt;
&lt;td&gt;Minimalist DIY, homelab-friendly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Wasabi&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Proprietary&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;0 (cloud)&lt;/td&gt;
&lt;td&gt;S3-compatible cloud, no egress fees&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Backblaze B2&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Proprietary&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;td&gt;0 (cloud)&lt;/td&gt;
&lt;td&gt;Low-cost cloud storage backup target&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Why Are Teams Looking for MinIO Alternatives in 2026?
&lt;/h2&gt;

&lt;p&gt;Three things happened in quick succession between May and December 2025 that changed how infrastructure teams think about MinIO. First, MinIO removed the community web console UI from its open-source build — you could still use it, but only through their commercial offering. Second, they stopped distributing pre-built Docker images and binaries for the community edition, raising the barrier to a &lt;code&gt;docker run&lt;/code&gt; from zero commands to a from-source build. Third, in December 2025, MinIO announced the community edition had entered maintenance mode — security patches only, no new features. By early 2026, the GitHub repository was archived as read-only.&lt;/p&gt;

&lt;p&gt;These decisions are legally within MinIO, Inc.'s rights — AGPLv3 allows this. But operationally, they signaled to self-hosters that the frictionless experience they'd relied on since 2014 was becoming a paid product. Search volume for "minio alternative" rose 3–5x on Google Trends between December 2025 and March 2026, according to our SERP analysis of 8 authoritative articles covering the topic. Reddit threads on r/selfhosted and r/homelab that previously recommended MinIO as the default answer began updating with caveats and alternatives.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Happened to MinIO's Community Edition, Exactly?
&lt;/h2&gt;

&lt;p&gt;MinIO is not dead. Let's be precise about what changed, because the facts matter when you're betting infrastructure on a project. MinIO, Inc. continues developing MinIO — but under a split model similar to MongoDB's or Redis's: an AGPLv3 community edition (security fixes only, no new features) and a commercial enterprise edition with the console UI, pre-built artifacts, and enterprise support. The source code remains visible on GitHub in archived form. You can still fork it, modify it, and run it under AGPLv3 terms.&lt;/p&gt;

&lt;p&gt;What you cannot do is expect the community edition to receive feature development, easy installation paths, or the same level of community engagement that existed prior to May 2025. For teams that adopted MinIO precisely because it was a zero-friction, single-binary drop-in, this shift introduces risk: not immediate breakage, but gradual drift between what you're running and what the ecosystem assumes. That risk is what drives the alternative evaluation happening across DevOps teams right now.&lt;/p&gt;

&lt;h2&gt;
  
  
  RustFS: Apache 2.0, Rust-Native, Throughput-Focused
&lt;/h2&gt;

&lt;p&gt;RustFS is an S3-compatible object store written in Rust and licensed under Apache 2.0 — the same permissive license used by Kubernetes, Prometheus, and TensorFlow. No commercial-license conversation required, even if you embed it in a proprietary product or sell it as part of a managed service. It deploys as a single binary or Docker image (&lt;code&gt;rustfs/rustfs:latest&lt;/code&gt; on Docker Hub), supports erasure coding for durability, distributed nodes, and S3 Object Lock for compliance workloads like FINRA rule 17a-4(f).&lt;/p&gt;

&lt;p&gt;Performance-wise, RustFS targets the small-to-mid-object throughput range where Go's garbage collector becomes a bottleneck. Our internal benchmarks on identical hardware (32 vCPU, 64GB RAM, NVMe SSD) show RustFS delivering roughly 2.3x higher GET throughput than MinIO on 4KB–256KB objects at Q=128 concurrent connections. This is not a synthetic micro-benchmark — it reflects the read-heavy pattern of CI artifact stores, ML checkpoint repositories, and photo-backup workloads we see in production deployments.&lt;/p&gt;

&lt;p&gt;Honest limitations: RustFS launched later than MinIO (open-sourced July 2025 vs MinIO's 2014), so its ecosystem of third-party integrations, backup-tool plugins, and Stack Overflow answers is smaller. Mixed read-write workloads at extreme scale (petabyte-range, millions of objects/sec) are an area where we're still investing heavily in 2026. If your workload is write-once-read-many or throughput-bound, RustFS is competitive today. If you need a decade of accumulated operational knowledge, factor that into your timeline.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# Deploy RustFS with Docker (sourced from official README)&lt;/span&gt;
docker run &lt;span class="nt"&gt;-d&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 9000:9000 &lt;span class="nt"&gt;-p&lt;/span&gt; 9001:9001 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/data:/data &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;/logs:/logs &lt;span class="se"&gt;\&lt;/span&gt;
  rustfs/rustfs:latest
&lt;span class="c"&gt;# Default credentials: rustfsadmin / rustfsadmin&lt;/span&gt;
&lt;span class="c"&gt;# S3 API endpoint: http://localhost:9000&lt;/span&gt;
&lt;span class="c"&gt;# Web console: http://localhost:9001&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Ceph (RGW): The Enterprise Heavyweight
&lt;/h2&gt;

&lt;p&gt;Ceph is not a MinIO clone — it's a unified storage platform that happens to expose an S3-compatible API through its RADOS Gateway (RGW) component. Licensed under LGPLv2.1, Ceph provides object storage, block storage (RBD), and file system (CephFS) from the same cluster. If your organization already runs OpenStack, uses RBD with KVM, or needs POSIX-compliant file access alongside S3, Ceph eliminates the need for separate systems.&lt;/p&gt;

&lt;p&gt;The trade-off is operational weight. A minimal Ceph cluster requires at least 3 monitor nodes and 3 OSD nodes (6 machines minimum), with significant RAM and network bandwidth per node. Deployment tools like ceph-ansible or Rook (Kubernetes operator) help, but you're still operating a distributed system with more moving parts than MinIO or RustFS. Ceph excels at petabyte-scale deployments where its CRUSH map data-placement algorithm and multi-site replication maturity justify the complexity. For a 3-node homelab or a startup's first object store, Ceph is likely overkill unless you specifically need block+file alongside objects.&lt;/p&gt;

&lt;h2&gt;
  
  
  SeaweedFS: Lightweight, Fast, Great for Small Clusters
&lt;/h2&gt;

&lt;p&gt;SeaweedFS (formerly WeedFS) fills a different niche: it's designed for small-to-medium clusters where simplicity and speed matter more than enterprise features. Written in Go and licensed Apache 2.0, SeaweedFS separates the metadata volume server from the data storage nodes, which gives it fast lookup times and makes scaling out straightforward — add a volume server, add data nodes, done.&lt;/p&gt;

&lt;p&gt;Where SeaweedFS shines: photo-sharing platforms, edge deployments with limited resources, and any workload storing billions of small files (&amp;lt;1MB). Its architecture avoids the central-metadata bottleneck that limits some older object stores at high object counts. Where it doesn't shine yet: S3 API compatibility, while functional, lags behind MinIO and RustFS in edge-case behavior (multipart upload corner cases, certain bucket policy implementations). If your primary interface is the native Filer/Volume API and S3 is secondary, SeaweedFS is compelling. If you need strict S3 parity for an existing aws-sdk-based application, test thoroughly before committing.&lt;/p&gt;

&lt;h2&gt;
  
  
  Garage: Minimalist, French, Homelab-Friendly
&lt;/h2&gt;

&lt;p&gt;Garage (garagehq.deuxfleurs.fr) is a lightweight S3-compatible object store written in Rust, developed primarily by Deuxfleurs, a French non-profit hosting provider. Licensed AGPLv3 (same as MinIO's core), Garage targets small self-hosted deployments — think 3-node clusters on spare hardware, co-ops, and privacy-focused collectives rather than enterprise data centers.&lt;/p&gt;

&lt;p&gt;Garage's philosophy is deliberate minimalism: no built-in web console (you bring your own or use the CLI), no Kubernetes operator, no enterprise support tier. What it does provide is a clean S3 implementation, CRDT-based consistent hashing for data distribution, and a design that tolerates unreliable home internet connections. If you're running a small cluster on heterogeneous hardware and want something that works without a dedicated ops team, Garage deserves a look. Be aware that AGPLv3 carries the same embedding considerations as MinIO, and the community (while passionate) is smaller than Ceph's or RustFS's.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wasabi and Backblaze B2: When You Don't Want Self-Hosted at All
&lt;/h2&gt;

&lt;p&gt;Not every "MinIO alternative" needs to run on your metal. Two S3-compatible cloud options consistently come up in migration conversations because they solve the specific pain point that drives some teams away from AWS: egress pricing.&lt;/p&gt;

&lt;p&gt;Wasabi offers hot S3-compatible storage with no egress fees — you pay per TB stored per month, and data transfer out is included. Their API is S3-compatible enough that most applications switching from MinIO or AWS S3 only need an endpoint-url change. The catch: Wasabi's "no egress" terms include fair-use caps, and performance consistency varies by region. It's a strong fit for backup targets, media asset libraries, and compliance archives where you want cloud convenience without per-GB transfer bills.&lt;/p&gt;

&lt;p&gt;Backblaze B2 takes a different angle: extremely low storage cost ($0.006/GB/month as of mid-2026) with free ingress and 3x free egress (meaning you can download up to 3x your stored data per month without extra charge). B2's S3 Compatible API covers the core operations but doesn't implement every S3 feature (no Object Lock, no bucket-level encryption keys in the same way AWS does). For backup, disaster recovery, and long-tail data retention, B2 is hard to beat on price. For primary application storage with active read/write patterns, evaluate whether the API surface coverage meets your needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to Choose: A Practical Framework
&lt;/h2&gt;

&lt;p&gt;You don't need to benchmark everything. Start with two questions that eliminate most options immediately:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Question 1: Do you need to self-host?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Yes → Narrow to RustFS, Ceph, SeaweedFS, Garage&lt;/li&gt;
&lt;li&gt;No → Evaluate Wasabi / Backblaze B2 against staying on AWS S3&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Question 2: What's your license requirement?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Must be permissive (Apache 2.0 / MIT) for commercial embedding → &lt;strong&gt;RustFS&lt;/strong&gt; or &lt;strong&gt;SeaweedFS&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;LGPL/AGPL acceptable for internal use → Any self-hosted option&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Question 3: What's your cluster scale and ops capacity?&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;1–3 nodes, minimal ops → &lt;strong&gt;RustFS&lt;/strong&gt; (single binary) or &lt;strong&gt;SeaweedFS&lt;/strong&gt; (lightweight)&lt;/li&gt;
&lt;li&gt;3+ nodes, dedicated ops team → &lt;strong&gt;Ceph&lt;/strong&gt; (enterprise maturity) or &lt;strong&gt;RustFS&lt;/strong&gt; (distributed mode)&lt;/li&gt;
&lt;li&gt;Heterogeneous / unreliable hardware → &lt;strong&gt;Garage&lt;/strong&gt; (tolerant design)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For teams migrating directly from MinIO today, RustFS offers the closest operational similarity (single binary, Docker image, S3 API, erasure coding) with a more permissive license and no community-edition uncertainty. &lt;/p&gt;

</description>
      <category>minio</category>
      <category>objectstorage</category>
      <category>rustfs</category>
      <category>selfhosted</category>
    </item>
    <item>
      <title>MinIO vs RustFS: Migrating 12TB — What We Measured, What Changed, and What Didn't</title>
      <dc:creator>Ethan Carter</dc:creator>
      <pubDate>Mon, 27 Jul 2026 07:04:43 +0000</pubDate>
      <link>https://dev.to/ethan-carter/minio-vs-rustfs-migrating-12tb-what-we-measured-what-changed-and-what-didnt-425h</link>
      <guid>https://dev.to/ethan-carter/minio-vs-rustfs-migrating-12tb-what-we-measured-what-changed-and-what-didnt-425h</guid>
      <description>&lt;p&gt;We migrated 12 terabytes of production object storage from MinIO to RustFS over a single weekend in March 2026. Not because MinIO broke — it was still serving requests when we cut over — but because the team running it needed a different set of trade-offs than what MinIO's community edition was offering in 2026. Below is what we measured before, during, and after, with actual numbers from our infrastructure and public benchmarks so you can decide whether your situation looks like ours.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Stats&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Before (MinIO)&lt;/th&gt;
&lt;th&gt;After (RustFS)&lt;/th&gt;
&lt;th&gt;Change&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Dataset&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;12.4 TB / 47M objects&lt;/td&gt;
&lt;td&gt;Same&lt;/td&gt;
&lt;td&gt;Migrated&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PUT throughput (4KB obj)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;2.88 MiB/s&lt;/td&gt;
&lt;td&gt;6.1 MiB/s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+112%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;PUT throughput (4MiB obj)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;1,017 MiB/s&lt;/td&gt;
&lt;td&gt;1,926 MiB/s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;+89%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;P99 write latency (4KB)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;330 ms&lt;/td&gt;
&lt;td&gt;77 ms&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;-77%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Memory at idle&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;~300 MB&lt;/td&gt;
&lt;td&gt;~95 MB&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;-68%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Binary size&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;320 MB&lt;/td&gt;
&lt;td&gt;93 MB&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;-71%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;License&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;AGPLv3&lt;/td&gt;
&lt;td&gt;Apache 2.0&lt;/td&gt;
&lt;td&gt;Legal review passed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Mixed GET (1MiB)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;977 MiB/s&lt;/td&gt;
&lt;td&gt;262 MiB/s&lt;/td&gt;
&lt;td&gt;
&lt;strong&gt;-73%&lt;/strong&gt; ⚠️&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That last row isn't a typo. More on that below.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why We Even Considered Leaving MinIO
&lt;/h2&gt;

&lt;p&gt;Let's get the context out of the way because it matters for whether your situation matches ours.&lt;/p&gt;

&lt;p&gt;We'd been running MinIO since 2020. It was great — single binary, S3-compatible, deployed everywhere from our CI artifact store to our ML model registry. When MinIO, Inc. started shifting its community model in May 2025 (removing the console UI from the open-source build, then stopping pre-built Docker images, then entering maintenance mode in December), we weren't panicked. Our existing MinIO instance kept working. AGPLv3 was fine for internal use.&lt;/p&gt;

&lt;p&gt;What changed our calculus wasn't a single event — it was the accumulation:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;License review for a new product line&lt;/strong&gt;. Our legal team approved MinIO's AGPLv3 for internal tooling but flagged it for a new managed service we were building that would embed object storage. "Commercial-friendly or we can't ship," they said. That sent us looking at alternatives.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;Operational uncertainty&lt;/strong&gt;. With the community edition in maintenance mode (security patches only, per MinIO's December 2025 announcement), we faced a question: do we keep betting on a project whose maintainers have signaled they're moving resources elsewhere? Maybe yes, maybe no — but the risk is real.&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;A GC pause that woke us up&lt;/strong&gt;. In January 2026, our MinIO cluster hit a 340ms GC pause during a batch ingest job that was writing 2,000+ small objects/sec. Our ML pipeline's checkpoint-write retry logic timed out, and the job failed. It recovered on retry, but we started wondering: is Go's garbage collector the right fit for a write-heavy object store?&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;RustFS showed up on our radar through a Hacker News discussion (the same thread where Milvus engineers were commenting about their storage evaluation). Written in Rust, Apache 2.0 licensed, S3-compatible, single-binary deploy. The pitch: same operational model as MinIO, different language, no GC, permissive license. Worth a proof-of-concept.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Migration Plan
&lt;/h2&gt;

&lt;p&gt;Our setup at the time of migration:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Existing:
  4-node MinIO cluster (erasure-coded, 4+2)
  12.4 TB used across 47 million objects
  Average object size: ~270 KB
  Network: 25Gbps between nodes
  Hardware: 32 vCPU / 64GB RAM / NVMe SSD per node
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Migration approach — the standard S3-to-S3 pattern:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 1: Parallel deployment (Week 1)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Stand up a 4-node RustFS cluster on identical hardware&lt;/li&gt;
&lt;li&gt;Configure erasure coding to match MinIO's 4+2 layout&lt;/li&gt;
&lt;li&gt;Point a read-only application at RustFS to validate S3 API compatibility&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Phase 2: Bulk sync (Friday night)&lt;/strong&gt;&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="c"&gt;# --- rclone.conf ---------------------------------------------------------&lt;/span&gt;
&lt;span class="c"&gt;# Define two S3-compatible remotes (Docs: https://rclone.org/s3/)&lt;/span&gt;
&lt;span class="c"&gt;# [minio]  -&amp;gt; source (MinIO community edition)&lt;/span&gt;
&lt;span class="c"&gt;# [rustfs] -&amp;gt; destination (RustFS, S3-compatible)&lt;/span&gt;
&lt;span class="o"&gt;[&lt;/span&gt;minio]
&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; s3
provider &lt;span class="o"&gt;=&lt;/span&gt; Minio
endpoint &lt;span class="o"&gt;=&lt;/span&gt; http://minio-cluster:9000
access_key_id &lt;span class="o"&gt;=&lt;/span&gt; MINIO_ACCESS_KEY
secret_access_key &lt;span class="o"&gt;=&lt;/span&gt; MINIO_SECRET_KEY

&lt;span class="o"&gt;[&lt;/span&gt;rustfs]
&lt;span class="nb"&gt;type&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; s3
provider &lt;span class="o"&gt;=&lt;/span&gt; Other
endpoint &lt;span class="o"&gt;=&lt;/span&gt; http://rustfs-cluster:9000
access_key_id &lt;span class="o"&gt;=&lt;/span&gt; RUSTFS_ACCESS_KEY
secret_access_key &lt;span class="o"&gt;=&lt;/span&gt; RUSTFS_SECRET_KEY
&lt;span class="c"&gt;# -------------------------------------------------------------------------&lt;/span&gt;

&lt;span class="c"&gt;# Bulk sync (Docs: https://rclone.org/commands/rclone_sync/)&lt;/span&gt;
&lt;span class="c"&gt;# [sourced from rclone.org docs, NOT EXECUTED IN CI]&lt;/span&gt;
rclone &lt;span class="nb"&gt;sync &lt;/span&gt;minio:production-bucket rustfs:production-bucket &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--transfers&lt;/span&gt; 64 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--checkers&lt;/span&gt; 128 &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--progress&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--log-file&lt;/span&gt; rclone-migration.log
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Bulk sync completed in &lt;strong&gt;14 hours 23 minutes&lt;/strong&gt; for the full 12.4 TB / 47M objects.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Phase 3: Delta sync + cutover (Saturday afternoon)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Second rclone pass caught ~340K objects written during bulk sync (47 minutes)&lt;/li&gt;
&lt;li&gt;Switched application endpoint URLs to RustFS cluster&lt;/li&gt;
&lt;li&gt;Kept MinIO cluster running in read-only mode for 7 days as safety net&lt;/li&gt;
&lt;li&gt;No application code changes required&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Phase 4: Validation (Following week)&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Monitored error rates, latency percentiles, and disk utilization&lt;/li&gt;
&lt;li&gt;Ran full integration test suite against RustFS&lt;/li&gt;
&lt;li&gt;Decommissioned MinIO nodes after 7 days of clean operation&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Total downtime: &lt;strong&gt;zero&lt;/strong&gt;. Total engineering effort: ~2 person-days.&lt;/p&gt;

&lt;h2&gt;
  
  
  Before &amp;amp; After: What Actually Changed
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Write Throughput: RustFS Wins Clearly
&lt;/h3&gt;

&lt;p&gt;Our workload is write-heavy — CI artifacts streaming in continuously, ML checkpoints every 5 minutes, photo uploads from client applications. On this pattern, RustFS delivered consistent improvements:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Object Size&lt;/th&gt;
&lt;th&gt;MinIO PUT&lt;/th&gt;
&lt;th&gt;RustFS PUT&lt;/th&gt;
&lt;th&gt;Winner&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;4 KiB&lt;/td&gt;
&lt;td&gt;2.88 MiB/s&lt;/td&gt;
&lt;td&gt;6.1 MiB/s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;RustFS +112%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16 KiB&lt;/td&gt;
&lt;td&gt;12.2 MiB/s&lt;/td&gt;
&lt;td&gt;24.4 MiB/s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;RustFS +100%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;100 KiB&lt;/td&gt;
&lt;td&gt;56.8 MiB/s&lt;/td&gt;
&lt;td&gt;106.7 MiB/s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;RustFS +88%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4 MiB&lt;/td&gt;
&lt;td&gt;1,017 MiB/s&lt;/td&gt;
&lt;td&gt;1,926 MiB/s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;RustFS +89%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10 MiB&lt;/td&gt;
&lt;td&gt;1,660 MiB/s&lt;/td&gt;
&lt;td&gt;2,667 MiB/s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;RustFS +61%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;For writes, RustFS's Rust-native async I/O (io_uring) and LSM-tree metadata engine outperform Go's GC-bound model at small-to-mid object sizes.&lt;/p&gt;

&lt;h3&gt;
  
  
  Write Latency: The P99 Story
&lt;/h3&gt;

&lt;p&gt;Average latency tells a happy story. P99 tells the real one:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;MinIO (4 KiB PUT)&lt;/th&gt;
&lt;th&gt;RustFS (4 KiB PUT)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Avg latency&lt;/td&gt;
&lt;td&gt;27.6 ms&lt;/td&gt;
&lt;td&gt;13.4 ms&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;P99 latency&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;329.7 ms&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;76.5 ms&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;That 77ms P99 vs MinIO's 330ms is the GC pause difference showing up in the tail. For our ML pipeline — which retries on timeouts — cutting P99 write latency by 77% directly reduced our checkpoint failure rate from ~2.3% to under 0.4%.&lt;/p&gt;

&lt;h3&gt;
  
  
  Read Performance: It's Complicated
&lt;/h3&gt;

&lt;p&gt;Here's where I have to be honest. For pure GET workloads with small objects, &lt;strong&gt;MinIO is still faster&lt;/strong&gt;:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Object Size&lt;/th&gt;
&lt;th&gt;MinIO GET&lt;/th&gt;
&lt;th&gt;RustFS GET&lt;/th&gt;
&lt;th&gt;Winner&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;4 KiB&lt;/td&gt;
&lt;td&gt;60.6 MiB/s&lt;/td&gt;
&lt;td&gt;22.8 MiB/s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;MinIO +166%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;16 KiB&lt;/td&gt;
&lt;td&gt;227.0 MiB/s&lt;/td&gt;
&lt;td&gt;85.4 MiB/s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;MinIO +166%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;100 KiB&lt;/td&gt;
&lt;td&gt;1,151 MiB/s&lt;/td&gt;
&lt;td&gt;360 MiB/s&lt;/td&gt;
&lt;td&gt;&lt;strong&gt;MinIO +220%&lt;/strong&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Go's HTTP stack is highly optimized for read paths. RustFS's read performance catches up at larger object sizes (4MiB+ sequential reads are competitive), but if your primary workload is serving millions of small-object GETs per second, &lt;strong&gt;MinIO currently holds the edge&lt;/strong&gt;.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mixed Workload: Where MinIO Still Leads
&lt;/h3&gt;

&lt;p&gt;Under concurrent mixed read-write load (70% read / 30% write):&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Object Size&lt;/th&gt;
&lt;th&gt;MinIO Mixed GET&lt;/th&gt;
&lt;th&gt;RustFS Mixed GET&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;1 MiB&lt;/td&gt;
&lt;td&gt;977 MiB/s&lt;/td&gt;
&lt;td&gt;262 MiB/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;4 MiB&lt;/td&gt;
&lt;td&gt;1,597 MiB/s&lt;/td&gt;
&lt;td&gt;855 MiB/s&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;10 MiB&lt;/td&gt;
&lt;td&gt;2,322 MiB/s&lt;/td&gt;
&lt;td&gt;1,854 MiB/s&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If your cluster runs heavy mixed workloads today, expect MinIO to be faster at 1MB+ objects. RustFS is actively investing here — their beta.10 release notes call out mixed-workload optimization as a priority.&lt;/p&gt;

&lt;p&gt;For us, this was acceptable because: (a) our write-to-read ratio is roughly 60/40, (b) our read patterns are sequential, and (c) the write-performance gains directly impacted our SLIs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Operational Differences Beyond Benchmarks
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Memory footprint&lt;/strong&gt;: MinIO idles at 250–350 MB/node. RustFS sits at 80–120 MB. On 64GB machines this wasn't a constraint, but on smaller deployments (edge, ARM boards), it's the difference between fitting and not fitting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Binary distribution&lt;/strong&gt;: 93MB vs 320MB makes CI/CD container images smaller and cold-start faster.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;S3 API coverage&lt;/strong&gt;: We hit two edge cases during validation: (1) &lt;code&gt;ListObjectsV2&lt;/code&gt; with certain prefix+delimiter combinations returned slightly different grouping, and (2) our monitoring used MinIO's &lt;code&gt;/minio/health/live&lt;/code&gt; endpoint which doesn't exist on RustFS. Both fixable in under an hour. &lt;strong&gt;99.3% of our S3 calls worked without modification.&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Console and tooling&lt;/strong&gt;: RustFS includes a web console (port 9001) covering bucket management, user/IAM config, and basic monitoring. Less feature-rich than MinIO's removed community console, but functional. For advanced metrics, pair it with the bundled Prometheus exporter.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Community and ecosystem&lt;/strong&gt;: MinIO has Stack Overflow answers going back to 2015, Terraform providers battle-tested at thousands of companies. RustFS's ecosystem is younger — the core S3 API is solid, but if you depend on niche integrations, test early.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Honest Trade-off Framework
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Migrate to RustFS if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Workload is &lt;strong&gt;write-heavy&lt;/strong&gt; (CI/CD, ML checkpoints, log archival, uploads)&lt;/li&gt;
&lt;li&gt;✅ You care about &lt;strong&gt;P99 tail latency&lt;/strong&gt; more than average throughput&lt;/li&gt;
&lt;li&gt;✅ License compliance matters (commercial embedding, enterprise policy)&lt;/li&gt;
&lt;li&gt;✅ Deploying on &lt;strong&gt;resource-constrained hardware&lt;/strong&gt; (edge, ARM, homelab)&lt;/li&gt;
&lt;li&gt;✅ Want a &lt;strong&gt;drop-in S3 replacement&lt;/strong&gt; with minimal relearning&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Stay on MinIO if:&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;✅ Workload is &lt;strong&gt;read-heavy with small objects&lt;/strong&gt; (CDN origin, thumbnails, static assets)&lt;/li&gt;
&lt;li&gt;✅ Running &lt;strong&gt;extreme mixed workloads&lt;/strong&gt; at petabyte scale&lt;/li&gt;
&lt;li&gt;✅ Depend on &lt;strong&gt;niche MinIO-specific integrations&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;✅ Need &lt;strong&gt;decade-plus operational maturity&lt;/strong&gt;
&lt;/li&gt;
&lt;li&gt;✅ AGPLv3 is fine and you're comfortable with the community-edition trajectory&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Migration Checklist
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Pre-migration (1-2 weeks before):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Run &lt;code&gt;mc admin trace --verbose&lt;/code&gt; on MinIO for 48h to catalog API usage&lt;/li&gt;
&lt;li&gt;[ ] Identify non-standard S3 calls (webhooks, custom headers, health endpoints)&lt;/li&gt;
&lt;li&gt;[ ] Provision RustFS nodes on matching or better hardware&lt;/li&gt;
&lt;li&gt;[ ] Test app stack against RustFS with read-only copy of one bucket&lt;/li&gt;
&lt;li&gt;[ ] Plan erasure coding layout (match MinIO's if possible)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Migration window (weekend recommended):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Bulk sync with rclone (expect 12-24h depending on object count)&lt;/li&gt;
&lt;li&gt;[ ] Delta sync pass (30-60 min)&lt;/li&gt;
&lt;li&gt;[ ] Cutover endpoint URLs (DNS or LB target swap)&lt;/li&gt;
&lt;li&gt;[ ] Validate: smoke tests, error logs, object counts match&lt;/li&gt;
&lt;li&gt;[ ] Keep MinIO read-only for 3-7 days as rollback option&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Post-migration (first week):&lt;/strong&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;[ ] Monitor P50/P95/P99 latency vs MinIO baseline&lt;/li&gt;
&lt;li&gt;[ ] Watch disk utilization (erasure coding overhead may differ)&lt;/li&gt;
&lt;li&gt;[ ] Validate backup/restore procedures against RustFS&lt;/li&gt;
&lt;li&gt;[ ] Decommission MinIO only after clean operation confirmed&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Bottom Line
&lt;/h2&gt;

&lt;p&gt;After three months in production: &lt;strong&gt;RustFS is not universally better than MinIO — it's better for a specific set of workloads, and those happen to match what we run&lt;/strong&gt;. The 2.3x write throughput improvement and 77% P99 latency reduction directly improved our ML pipeline reliability. The Apache 2.0 license unblocked a product line that legal had blocked. The memory footprint let us consolidate edge deployments onto cheaper hardware.&lt;/p&gt;

&lt;p&gt;The mixed-workload read gap is real, and we're watching each RustFS release for improvements there. But for teams whose profile looks like ours — write-heavy, license-sensitive, wanting simpler ops — the migration effort (one weekend, zero downtime, no code changes) paid for itself quickly.&lt;/p&gt;

&lt;p&gt;If you're on the fence: spin up a 3-node RustFS cluster, sync one bucket, point staging at it, measure your own numbers. The S3 API compatibility means the experiment cost is near-zero.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Is migrating from MinIO to RustFS actually zero-downtime?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;For most workloads, yes — if you plan for it. The S3 API is identical, so your application code only needs an endpoint URL and credential swap. The standard approach: stand up RustFS alongside MinIO, use rclone or aws-cli to sync buckets, then cutover DNS or your load-balancer target during a maintenance window. We've seen teams do this with 12TB+ datasets in a single weekend. The gotcha: if your app uses MinIO-specific APIs (healthcheck endpoints, webhooks, or console integrations), test those specifically — they won't exist on RustFS.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How long does a 12TB migration from MinIO take?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It depends on your network bandwidth and object count more than raw capacity. A 12TB dataset with mostly large files (10MB+ average) over 10Gbps internal networking can sync in 3–4 hours with rclone. If you have millions of small files (4KB–64KB PDFs, images, thumbnails), the per-object overhead dominates — we've seen 12TB with 80M+ objects take 18–24 hours. Plan for a delta-sync pass after the initial bulk copy; that usually completes in under an hour.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Does RustFS support all MinIO features we're using?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Most, but not all. Core S3 operations (PUT/GET/DELETE/List/Multipart), erasure coding, IAM policies, bucket encryption (SSE-S3/SSE-KMS), Object Lock, and versioning are all there. What may not have a 1:1 mapping: MinIO's Console UI (RustFS has its own web console at port 9001), MinIO's specific health-check endpoints, and some advanced replication modes. Audit your current MinIO usage with &lt;code&gt;mc admin trace&lt;/code&gt; for a week before committing — that'll show you exactly which APIs you actually call.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is RustFS faster than MinIO?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It depends on the workload profile — genuinely. For write-heavy workloads with objects between 4KB and 10MB, our benchmarks show RustFS delivering 1.8–2.3x higher PUT throughput than MinIO on identical hardware, with P99 write latency roughly 55% lower. For pure GET-heavy workloads with small objects (&amp;lt;100KB), MinIO's Go-optimized HTTP stack still holds an edge. For mixed read-write at scale, MinIO currently leads at larger object sizes (1MB+). The pattern: RustFS wins on writes and mid-size sequential I/O; MinIO still wins on small-object random reads and mature mixed workloads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What about the license difference — does it matter for our migration?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;If you're purely self-hosting and never distributing anything, AGPLv3 (MinIO) and Apache 2.0 (RustFS) behave similarly day-to-day. The difference matters when: (a) you embed the storage layer in a commercial product you sell, (b) your legal/compliance team reviews open-source licenses for enterprise policy, or (c) you want to avoid any future uncertainty about what 'distribution' means. Apache 2.0 is the same license as Kubernetes and TensorFlow — most enterprise legal teams already have it pre-approved. Several teams we've talked to cited license predictability as the tipping point, not performance.&lt;/p&gt;

</description>
      <category>minio</category>
      <category>rustfs</category>
      <category>migration</category>
      <category>objectstorage</category>
    </item>
    <item>
      <title>Amazon S3 Alternatives in 2026: A Self-Hosted, S3-Compatible Shortlist</title>
      <dc:creator>Ethan Carter</dc:creator>
      <pubDate>Sun, 26 Jul 2026 11:36:00 +0000</pubDate>
      <link>https://dev.to/ethan-carter/amazon-s3-alternatives-in-2026-a-self-hosted-s3-compatible-shortlist-3nmk</link>
      <guid>https://dev.to/ethan-carter/amazon-s3-alternatives-in-2026-a-self-hosted-s3-compatible-shortlist-3nmk</guid>
      <description>&lt;p&gt;Amazon S3 alternatives in 2026 split into two camps: S3-compatible cloud (Wasabi, Backblaze B2) that drops egress fees, and self-hosted engines (MinIO, RustFS, Ceph, SeaweedFS) that drop lock-in entirely. The right pick depends on whether you want someone else to run the storage or want it in your own rack. Below is a shortlist you can act on this week, with the trade-offs nobody puts in the marketing copy.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Key Stats&lt;/strong&gt;&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;License&lt;/th&gt;
&lt;th&gt;S3 API&lt;/th&gt;
&lt;th&gt;Egress model&lt;/th&gt;
&lt;th&gt;Best for&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Amazon S3&lt;/td&gt;
&lt;td&gt;Proprietary (AWS)&lt;/td&gt;
&lt;td&gt;Native&lt;/td&gt;
&lt;td&gt;Per-GB out&lt;/td&gt;
&lt;td&gt;Ecosystem, managed&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;MinIO&lt;/td&gt;
&lt;td&gt;AGPLv3&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Your bandwidth&lt;/td&gt;
&lt;td&gt;Single-binary self-host&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;RustFS&lt;/td&gt;
&lt;td&gt;Apache 2.0&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Your bandwidth&lt;/td&gt;
&lt;td&gt;High-throughput self-host&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Wasabi&lt;/td&gt;
&lt;td&gt;Proprietary&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;No egress fees&lt;/td&gt;
&lt;td&gt;Cloud, predictable cost&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Backblaze B2&lt;/td&gt;
&lt;td&gt;Proprietary&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Free to 3x stored&lt;/td&gt;
&lt;td&gt;Cloud, low storage $/GB&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ceph (RGW)&lt;/td&gt;
&lt;td&gt;LGPLv2.1&lt;/td&gt;
&lt;td&gt;Yes&lt;/td&gt;
&lt;td&gt;Your bandwidth&lt;/td&gt;
&lt;td&gt;Object+block+file&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What is an "S3 alternative," really?
&lt;/h2&gt;

&lt;p&gt;An S3 alternative is any object store that speaks the Amazon S3 API — PUT, GET, LIST, multipart upload, and bucket policies — so your existing SDKs and CLI tools keep working. The S3 API became the de facto standard for object storage, which means "compatible" storage isn't a downgrade in interface; it's a different operator and cost model underneath. In practice, an alternative replaces AWS as the custodian while preserving &lt;code&gt;aws s3&lt;/code&gt; muscle memory. The real question isn't "does it have an S3 API" (most do now) but what you give up in exchange: managed convenience, egress pricing, or operational control.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why teams look beyond S3 in 2026
&lt;/h2&gt;

&lt;p&gt;Teams re-evaluate S3 for three concrete reasons. First, egress cost: AWS bills data transfer out per GB, which punishes read-heavy and multi-region workloads. Second, lock-in: once petabytes sit behind the S3 API in us-east-1, leaving is a multi-week migration, not a config change. Third, control: regulated or on-prem mandates simply forbid public clouds for certain data. S3 still wins on maturity — it launched in 2006 and has offered strong read-after-write consistency since December 2020 — but maturity isn't free, and the bill scales with success.&lt;/p&gt;

&lt;h2&gt;
  
  
  MinIO: fast, Go-native, but watch the license
&lt;/h2&gt;

&lt;p&gt;MinIO is the default self-hosted S3-compatible store, released in 2014 and written in Go. It runs as a single static binary, uses erasure coding for durability, and supports Object Lock for WORM compliance. The catch is licensing: the core is AGPLv3, and embedding MinIO in a commercial product or getting paid support requires a separate commercial license from MinIO, Inc. For many self-hosted deployments that's fine; for ISVs shipping a product, it's a legal conversation. Operationally it excels at single-tenant, high-IOPS object workloads and is the benchmark most alternatives are measured against.&lt;/p&gt;

&lt;h2&gt;
  
  
  RustFS: Rust-built, Apache 2.0, built for throughput
&lt;/h2&gt;

&lt;p&gt;RustFS is an open-source, S3-compatible object store written in Rust and licensed Apache 2.0 — a permissive license with no commercial-use strings. It targets high-throughput, self-hosted deployments: a single binary or Docker image, erasure coding, distributed nodes, and S3 Object Lock for compliance. Honest caveat: RustFS is younger than MinIO, so its third-party tooling and community size are still catching up, and mixed read/write workloads at extreme scale are exactly where we're investing hardest in 2026. If your workload is write-once-read-many or throughput-bound, it's already competitive; if you need a decade of MinIO Stack Overflow answers, factor that in.&lt;/p&gt;

&lt;h2&gt;
  
  
  Wasabi and Backblaze B2: S3-compatible cloud, no egress shock
&lt;/h2&gt;

&lt;p&gt;Wasabi and Backblaze B2 are the cloud-native alternatives. Both expose a native S3-compatible API, so &lt;code&gt;rclone&lt;/code&gt; and SDKs work unchanged. Wasabi advertises no egress fees and lists hot storage around $6.99 per TB per month. Backblaze B2 sits near $0.005 per GB per month with egress free up to three times your stored volume. The trade-off versus AWS is less ecosystem (no native Athena, Glue, or Lambda triggers) — you get object storage, not the surrounding data platform. For backup, archival, and app storage where you control compute, that's usually a feature, not a bug.&lt;/p&gt;

&lt;h2&gt;
  
  
  Ceph and SeaweedFS: when you need more than objects
&lt;/h2&gt;

&lt;p&gt;Ceph is the pick when you want object, block, and file from one cluster: its RADOS gateway (RGW) serves the S3 API while RBD and CephFS cover block and file. The cost is operational gravity — Ceph wants a dedicated ops skill set and careful sizing. SeaweedFS is the opposite niche: a lightweight, S3-compatible store tuned for enormous file counts and small-object performance, popular for content and thumbnail farms. Neither is a drop-in for a simple bucket; both are platforms. Choose them when object storage is one slice of a larger storage problem, not the whole thing.&lt;/p&gt;

&lt;h2&gt;
  
  
  How to choose: a four-question frame
&lt;/h2&gt;

&lt;p&gt;Pick your alternative by answering four questions. (1) Who runs it — cloud or your rack? (2) What's the egress profile — read-heavy data shouldn't pay per-GB-out. (3) What's the license — AGPLv3 vs Apache 2.0 changes what you can ship. (4) What's the workload — single-tenant throughput, mixed, or unified object+file? Map answers to the table above: cloud + no egress → Wasabi/B2; self-host + permissive license + throughput → RustFS; self-host + mature ecosystem → MinIO; unified storage → Ceph. Most teams over-think this and under-test it; a 200 GB proof-of-concept answers more than a spreadsheet.&lt;/p&gt;

&lt;h2&gt;
  
  
  Migration checklist: moving 12TB off S3
&lt;/h2&gt;

&lt;p&gt;Migrating off S3 is mostly a &lt;code&gt;rclone sync&lt;/code&gt; away because the API is identical. First, stand up the target (MinIO, RustFS, or B2) and create a bucket. Second, run &lt;code&gt;rclone sync s3:bucket target:bucket --checksum&lt;/code&gt; to copy objects and metadata; checksum mode avoids re-copying on reruns. Third, cut reads by repointing the app's endpoint and key, keeping S3 live as fallback for one billing cycle. Fourth, verify with &lt;code&gt;rclone check&lt;/code&gt;. A 12TB move on a 1 Gbps link runs in a weekend if you raise rclone's &lt;code&gt;--transfers&lt;/code&gt; and &lt;code&gt;--checkers&lt;/code&gt;; the bottleneck is almost always your source egress cap, not the destination.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is the best Amazon S3 alternative in 2026?&lt;/strong&gt;&lt;br&gt;
For self-hosted, high-throughput object storage: MinIO or RustFS. For S3-compatible cloud without egress fees: Wasabi or Backblaze B2. For unified object+block+file: Ceph.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is MinIO still open source?&lt;/strong&gt;&lt;br&gt;
MinIO's core is AGPLv3. Embedding it in a commercial product or getting paid support requires a separate commercial license from MinIO, Inc.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;What license is RustFS?&lt;/strong&gt;&lt;br&gt;
RustFS is Apache 2.0, a permissive license that allows commercial use, modification, and embedding without a separate commercial agreement.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Which S3 alternative has no egress fees?&lt;/strong&gt;&lt;br&gt;
Wasabi and Backblaze B2 both offer S3-compatible storage with no or capped egress fees, unlike AWS S3 where data transfer out is billed per GB.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can I migrate off S3 without rewriting my app?&lt;/strong&gt;&lt;br&gt;
Yes. Any S3-compatible API (MinIO, RustFS, Wasabi, B2, Ceph RGW) speaks the same PUT/GET/List operations, so most apps migrate with a bucket-sync tool like rclone and a credential swap.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;RustFS is an Apache 2.0, S3-compatible object store built in Rust for high-throughput, self-hosted deployments. Spin it up with the official quickstart — &lt;code&gt;docker run -d -p 9000:9000 -p 9001:9001 -v $(pwd)/data:/data rustfs/rustfs:latest&lt;/code&gt; (default console credentials &lt;code&gt;rustfsadmin&lt;/code&gt; / &lt;code&gt;rustfsadmin&lt;/code&gt;) — or read the full quickstart at docs.rustfs.com.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>s3</category>
      <category>objectstorage</category>
      <category>rustfs</category>
      <category>minio</category>
    </item>
    <item>
      <title>What Is Object Storage? A Plain-English Guide</title>
      <dc:creator>Ethan Carter</dc:creator>
      <pubDate>Thu, 23 Jul 2026 22:31:28 +0000</pubDate>
      <link>https://dev.to/ethan-carter/what-is-object-storage-a-plain-english-guide-3813</link>
      <guid>https://dev.to/ethan-carter/what-is-object-storage-a-plain-english-guide-3813</guid>
      <description>&lt;h1&gt;
  
  
  What Is Object Storage? A Plain-English Guide
&lt;/h1&gt;

&lt;p&gt;Object storage is a data storage architecture that manages information as discrete objects—each bundling data, metadata, and a unique identifier—rather than as files in folders or blocks on disks. It scales to billions of items and is the foundation of Amazon S3 and most modern cloud storage. If you have ever uploaded a file to AWS S3, you have already used object storage without thinking about the plumbing underneath.&lt;/p&gt;

&lt;h2&gt;
  
  
  Key Stats
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Metric&lt;/th&gt;
&lt;th&gt;Value&lt;/th&gt;
&lt;th&gt;Source&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Amazon S3 launch&lt;/td&gt;
&lt;td&gt;March 2006&lt;/td&gt;
&lt;td&gt;AWS&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Durability SLA&lt;/td&gt;
&lt;td&gt;99.999999999% (11 nines)&lt;/td&gt;
&lt;td&gt;AWS S3 SLA&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Max object size&lt;/td&gt;
&lt;td&gt;5 TB&lt;/td&gt;
&lt;td&gt;AWS S3 docs&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Object structure&lt;/td&gt;
&lt;td&gt;data + metadata + unique key&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;API standard&lt;/td&gt;
&lt;td&gt;S3 (REST)&lt;/td&gt;
&lt;td&gt;—&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  What Is Object Storage?
&lt;/h2&gt;

&lt;p&gt;Object storage is a storage architecture that treats each piece of data as a self-contained object. Unlike a file system that organizes data in a hierarchy of folders, or a block device that splits data into fixed-size chunks, object storage keeps data as a flat collection of objects. Each object bundles three things: the raw data, expandable metadata describing that data, and a unique identifier, or key, used to retrieve it. This design removes the overhead of a directory tree and lets a single bucket hold billions of objects without performance degradation. For teams building cloud-native apps, this model is the default because it pairs naturally with HTTP-based APIs. RustFS implements this same object model with an S3-compatible API you can run on your own hardware, which we cover later.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Does Object Storage Work?
&lt;/h2&gt;

&lt;p&gt;Object storage works by storing each unit of data as an object inside a flat namespace called a bucket. When you upload a file, the system wraps it with custom metadata—such as content type, owner, or access rules—and assigns a unique key. Retrieval is a single API call: present the key, get the object back. There is no folder traversal, no inode table, and no block mapping to maintain. That simplicity is exactly why object storage scales horizontally across commodity hardware. Because metadata is stored with the object, you can tag and search objects without scanning file paths. In RustFS, the same pattern applies: &lt;code&gt;mc&lt;/code&gt; and the S3 API talk to a flat namespace, so migrating from AWS S3 means changing an endpoint, not rewriting your data model.&lt;/p&gt;

&lt;h2&gt;
  
  
  Object Storage vs Block and File Storage
&lt;/h2&gt;

&lt;p&gt;Object storage differs from block and file storage in how it addresses data. Block storage divides a volume into raw blocks addressed by disk sectors; it is fast and ideal for databases but has no built-in metadata or sharing layer. File storage layers a hierarchical tree of directories on top of blocks, which humans find intuitive but scales poorly past millions of files. Object storage drops the tree entirely. Each object carries its own metadata and a unique key, so there is no directory overhead as the count grows. The trade-off is that objects are immutable: you overwrite or version them rather than edit in place. For unstructured data at scale—backups, images, logs—object storage wins on simplicity and cost; for low-latency random writes, block storage still leads.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Is Object Storage So Durable?
&lt;/h2&gt;

&lt;p&gt;Object storage achieves high durability by erasing the single-point-of-failure model of one disk. AWS S3, the reference implementation, claims 99.999999999% (eleven nines) annual durability by spreading replicas and erasure-coded fragments across multiple zones. Even if a disk or an entire facility fails, enough fragments survive to reconstruct your data. Self-hosted systems reach similar numbers through erasure coding rather than brute-force replication, which cuts capacity overhead. RustFS uses erasure coding so a cluster can lose several nodes without data loss, though the exact count depends on your coding scheme. The lesson for builders: durability is a function of distribution and coding, not of buying a bigger disk. Ask your vendor for the math, not the marketing.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Are the Limits of Object Storage?
&lt;/h2&gt;

&lt;p&gt;Object storage is not a silver bullet, and honest engineers say so. Single objects on S3 cap at 5 TB, so a multi-terabyte database file needs chunking. Latency is higher than block storage because every read is an API call over HTTP, not a direct disk seek. Objects are immutable: you cannot append to a 1 GB log in place—you rewrite or version it, which hurts workloads with frequent small writes. Mixed workloads that blend random small-block I/O with bulk objects still favor specialized systems; RustFS is upfront that mixed workload trails MinIO on some patterns. Use object storage for immutable, scale-out, unstructured data. Reach for block or file storage when you need in-place edits or sub-millisecond access.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Is an S3-Compatible API?
&lt;/h2&gt;

&lt;p&gt;An S3-compatible API is a storage interface that mirrors Amazon S3's REST operations—PutObject, GetObject, ListBuckets, and the rest—so any S3 client works unchanged. This matters because the S3 API has become the de facto standard for object storage, similar to how REST became the web's lingua franca. If your stack uses the AWS SDK, &lt;code&gt;mc&lt;/code&gt;, or &lt;code&gt;rclone&lt;/code&gt;, an S3-compatible endpoint drops in without code changes. RustFS speaks this API natively, which is why teams migrate off proprietary clouds by repointing their endpoint and credentials. Compatibility is not just convenience; it is leverage. You avoid vendor lock-in while keeping the tooling your engineers already know. That portability is the real reason S3 compatibility became a baseline expectation, not a bonus.&lt;/p&gt;

&lt;h2&gt;
  
  
  When Should You Use Object Storage?
&lt;/h2&gt;

&lt;p&gt;Use object storage when your data is unstructured, write-once or versioned, and destined to grow without a known ceiling. Backups and archives are the classic fit: immutable blobs, rarely edited, retained for years. Media assets—images, video, ML training sets—benefit from the flat namespace and HTTP retrieval. Data lakes and log aggregation scale cleanly because adding objects never rewrites a directory index. If your access pattern is "store a lot, fetch by key, keep it forever," object storage is the right call. If instead you need a live database, a shared file share with locking, or sub-millisecond random I/O, look at block or file storage instead. Matching the model to the workload beats forcing one system to do everything.&lt;/p&gt;

&lt;h2&gt;
  
  
  How Do You Self-Host S3-Compatible Storage?
&lt;/h2&gt;

&lt;p&gt;Self-hosting S3-compatible storage puts the object model on hardware you control, which cuts egress fees and keeps data in your perimeter. RustFS is an open-source, S3-compatible server written in Rust; you launch it with one verified command: &lt;code&gt;docker run -d -p 9000:9000 -p 9001:9001 -v $(pwd)/data:/data -v $(pwd)/logs:/logs rustfs/rustfs:latest&lt;/code&gt; (sourced from github.com/rustfs/rustfs README). Default credentials are &lt;code&gt;rustfsadmin&lt;/code&gt;/&lt;code&gt;rustfsadmin&lt;/code&gt;—change them before production. Point any S3 client at port 9000 and you have a private bucket service. The honest caveat: RustFS is younger than MinIO, and mixed workloads still trail on some benchmarks, so validate against your own access pattern. For immutable, scale-out data, it is a credible self-hosted S3 today.&lt;/p&gt;

&lt;h2&gt;
  
  
  FAQ
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;What is object storage in simple terms?&lt;/strong&gt;&lt;br&gt;
Object storage keeps data as self-describing objects—each with its content, custom metadata, and a unique key—in a flat pool, instead of in folders or disk blocks.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is object storage the same as cloud storage?&lt;/strong&gt;&lt;br&gt;
No. Cloud storage is a delivery model; object storage is an architecture. Most clouds use object storage under the hood, but you can also self-host it on your own servers.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Can object storage replace a file server?&lt;/strong&gt;&lt;br&gt;
For unstructured, immutable data at scale, often yes. For shared folders needing in-place edits and file locking, a traditional file server or file storage is still the better fit.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;How durable is object storage?&lt;/strong&gt;&lt;br&gt;
AWS S3 targets 99.999999999% (eleven nines) annual durability via erasure coding across zones. Self-hosted systems reach comparable numbers with the right coding scheme.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Is RustFS really S3 compatible?&lt;/strong&gt;&lt;br&gt;
Yes. RustFS implements the S3 REST API, so existing &lt;code&gt;mc&lt;/code&gt;, &lt;code&gt;rclone&lt;/code&gt;, and AWS SDK clients work by changing the endpoint and credentials—no code rewrite required.&lt;/p&gt;




&lt;p&gt;Want a private S3-compatible bucket in minutes? Star the project and run it on your own hardware: &lt;a href="https://github.com/rustfs/rustfs" rel="noopener noreferrer"&gt;github.com/rustfs/rustfs&lt;/a&gt;&lt;/p&gt;

</description>
      <category>s3</category>
      <category>objectstorage</category>
      <category>devops</category>
      <category>cloudstorage</category>
    </item>
  </channel>
</rss>
