Atomic Rename Guarantees Across Cloud Storage Backends

S3 Express One Zone finally adds atomic rename, but only for a narrow slice of AWS's storage lineup.

Contributing Editor · · 13 min read
Cover illustration for “Atomic Rename Guarantees Across Cloud Storage Backends”
POSIX Semantics · September 12, 2026 · 13 min read · 2,934 words

S3 Standard has no rename API, and it never will. Not because AWS is dragging its feet, but because S3's namespace model has no concept of a directory to begin with. There's nothing to rename, structurally speaking. Only a flat list of keys.

Under the hood, tools like S3A (the Hadoop connector for S3) handle a "rename" the only way they can: server-side copy to the destination key, then delete the source key. For a single file, that's two calls. For a directory with a thousand files in it, that's a thousand copies followed by a thousand deletes, run one after another or in batches. The cost scales with file count, not with some fixed metadata operation, and that's the whole problem in one sentence.

Back in late 2020, S3 picked up strong read-after-write consistency, which killed off a nasty class of bugs where a listing would return stale results right after a write. Genuine improvement. It never touched rename, though, and the rename problem persists even on a fully consistent S3, because consistency and atomicity are two different guarantees. S3 only ever fixed the first one.

Here's what actually breaks in production when engineers assume otherwise:

  • Copy succeeds, delete fails. Both objects exist now, and downstream code has to guess which one is "real."
  • Copy fails mid-directory. Some files land at the new path, others sit stranded at the old one, with no marker saying the move is incomplete.
  • Two processes rename the same object at once. Nothing in S3 stops this, and nothing tells you it happened.

None of this makes S3 Standard a bad product. It's the most widely used object store on the planet, and the missing rename is a documented constraint, not a defect. But if a pipeline leans on rename as a signal that something finished, correctly, atomically, it's leaning on a guarantee that was never there. Know that before you build on it, because the failure shows up downstream, not at the call site where the mistake actually happened.

That changes, at least in one narrow corner of AWS's product line.

What S3 Express One Zone's RenameObject API actually guarantees, and where it stops

As of June 2025, S3 Express One Zone ships a RenameObject API, and it does something genuinely new: it renames an object in a single API call. No copying. No deleting. Just a metadata pointer update, the same trick a regular filesystem has been doing for decades.

The performance gap this closes isn't subtle. Renaming a 1-terabyte object the old copy-then-delete way could take hours. With RenameObject, the same move finishes in milliseconds, because nothing actually moves. Only the pointer changes.

Read the fine print before getting excited, though:

  • This only works in directory buckets, the storage format specific to S3 Express One Zone.
  • It only works within the same bucket.
  • S3 Standard, S3 Intelligent-Tiering, S3 Standard-IA, and every other storage class are left out entirely.

You reach the API through the AWS SDKs, the AWS CLI, the Management Console, the S3 API directly, or Mountpoint for Amazon S3 (version 1.19.0 and up). The Hadoop project noticed fast, and its documentation flags that same SDK version as the entry point for teams wiring this into existing tooling.

Some context on why Express One Zone exists at all: AWS launched it in November 2023 for latency-sensitive workloads that need single-digit-millisecond response times. It moves data up to 10 times faster than S3 Standard and cuts request costs roughly in half, by AWS's own figures. Atomic rename is one more feature bolted onto that performance-first product, not a general upgrade to S3 as a whole. Treating it as one is the exact mistake to avoid here.

So if a pipeline currently runs on S3 Standard, atomic rename doesn't show up as a free software update. Getting it means migrating to directory buckets in Express One Zone, which is a real architectural decision with real tradeoffs: single-AZ durability instead of multi-AZ, and a different pricing model entirely. Worth it for latency-bound workloads. Overkill for a nightly batch job that never needed rename correctness in the first place.

How Google Cloud Storage's hierarchical namespace delivers atomic rename

Standard Google Cloud Storage buckets have the same flat-namespace problem as S3 Standard. Rename means copy, then delete. Same two-step dance, same gap in the middle where things go wrong.

Google's fix is a bucket-level setting called hierarchical namespace, or HNS. Turn it on, and folders stop being a naming convention (a prefix pretending to be a directory) and become real objects with their own metadata. That one change makes atomic rename possible, because a folder rename becomes a single metadata update on a single object, not a sweep through every key that happens to share a prefix.

Whole folders move atomically too, contents and all, in one operation. Google's own figures put HNS buckets at 8 times the read/write throughput (measured in queries per second) compared to buckets without it. Google's documentation calls out high-throughput data loading and frequent checkpointing as the workloads that benefit most, which tells you exactly who this feature was built for.

There's also a newer tier worth knowing: Rapid Storage, announced at Google Cloud Next 2025 and later referred to as Cloud Storage Rapid. It's zonal buckets with HNS baked in, aimed squarely at I/O-heavy AI and ML training. Google's published specs claim over 15 terabytes per second of bandwidth, 20 million requests per second, and sub-millisecond latency. Those numbers exist because training jobs choke on exactly the kind of storage latency this tier is built to remove.

One more piece worth flagging: Cloud Storage FUSE, which mounts a GCS bucket as if it were a local filesystem, on a VM, inside a GKE pod, or on an on-prem box. With HNS enabled, the bucket gains the metadata structure that filesystem-style operations depend on.

Google backs all of GCS with 11 nines of annual durability and strong global consistency across operations. Here's the catch, and it's not a small one: HNS gets decided at bucket creation, with no in-place upgrade path. An existing flat bucket can't be flipped over to hierarchical namespace after the fact. If atomic rename matters, plan for it before provisioning the bucket. There's no fixing it after.

How Azure Data Lake Storage Gen2 makes atomic rename the default for analytics workloads

Standard Azure Blob Storage tells the same story as S3 and vanilla GCS: flat namespace, copy-then-delete rename, all the same failure modes waiting to happen.

Azure Data Lake Storage Gen2 (ADLS Gen2) fixes this by layering a hierarchical namespace on top of Blob Storage, so directories become real, first-class objects instead of a naming trick. Renaming a directory becomes a single metadata operation, and it completes in constant time no matter how big the directory is.

The scale of the difference is worth sitting with. Take a directory with 10,000 files in it. On flat Blob Storage, renaming it means a large number of copy and delete calls, one pair per file, plus any listing overhead. On ADLS Gen2, it's one metadata update, full stop.

The rename completes as a single metadata operation, O(1) performance, meaning the time it takes doesn't grow with the number of files inside. Microsoft's own cost guidance notes that compute makes up more than 85% of total workload cost in most cloud analytics setups, so shaving latency off something as unglamorous as a commit-time rename actually moves the total cost of ownership, not just the stopwatch on one job.

ADLS Gen2 is reachable through Blob-compatible APIs and the HDFS-compatible ABFS driver, meaning direct, native access from Spark, Hadoop, Databricks, Synapse, and Fabric. That's most of the enterprise analytics stack running on Azure today, which is exactly why this decision matters more than it looks like on paper.

One thing here is permanent, and worth flagging before touching it: once hierarchical namespace gets turned on for a storage account, there's no turning it back off. It's a one-way door. Enable it because the workload actually needs it, not because it sounded like a nice-to-have in a planning meeting.

Azure Blob Storage holds roughly 24% of the global cloud storage market, and ADLS Gen2 is the version most Spark and Databricks users on Azure eventually run into, whether they planned for it or not.

Cloudflare R2 and the backends that don't offer atomic rename

Cloudflare R2 sells itself on an S3-compatible API, zero egress fees, and storage that spreads across Cloudflare's edge network automatically. Good pitch, and a fair one. None of it touches filesystem semantics, though. R2's differentiator is pricing and network placement, not how rename works, and confusing the two is the mistake to avoid here.

Because R2 speaks the S3 API, it inherits S3's rename behavior too, meaning there isn't any. Same copy-then-delete limitation, same gap, same risk if a delete fails after a copy succeeds. R2 keeps the feature set lean elsewhere as well: two storage classes (Standard and Infrequent Access), no deep archive tier, and bucket locks for retention policies. That's a fair trade, smaller feature surface for zero egress and less operational overhead, for a lot of workloads. Atomic rename just isn't part of the deal, and R2 never claimed otherwise.

The same goes for other S3-compatible stores: self-hosted MinIO clusters and similar products. If a store implements the S3 API, it inherits the S3 API's rename gap, unless somebody has explicitly bolted a filesystem layer on top to fill it in. Compatibility with S3's interface is not the same thing as fixing S3's structural limitation. Teams get burned constantly assuming "S3-compatible" means "S3-equivalent," and it doesn't.

This cuts both ways depending on configuration, not just on provider. Standard Azure Blob Storage without ADLS Gen2's hierarchical namespace turned on has the same flat-namespace problem. Standard GCS without HNS enabled has it too. Practically every provider now offers S3 API compatibility as table stakes, and that baseline carries the rename limitation right along with it. Being S3-compatible tells you nothing about rename atomicity, one way or the other, and asking the question at the API level is asking the wrong question entirely.

The real decision was never "which cloud provider." It's which specific configuration, on which specific provider, actually delivers atomic rename: directory buckets on Express One Zone, a hierarchical-namespace bucket on GCS, hierarchical namespace on Azure. Atomic rename isn't a property of "object storage" as a category. Treat it like one and the assumption breaks on you, usually at the worst possible time.

Why distributed systems make atomic rename hard to implement at cloud scale

Object storage gets its scale by splitting metadata across domains that each manage their own slice independently. That design choice is exactly what makes rename hard, because a rename needs atomicity and strong consistency across metadata owners simultaneously, and those owners were never built to coordinate with each other. This is the clearest framing of why this problem resists easy fixes.

Picture the source key and destination key hashing to two different shards. The rename now spans two metadata domains that share no storage, no global lock, and no shared clock to agree on ordering. There's no single table to update, because there's no single table to begin with.

Building a correct rename protocol under those conditions, per the IEEE presentation, means treating rename as a multi-stage, recoverable state machine: explicit transaction tracking, invariants that hold locally on each shard, and transitions that are idempotent, so a failure or a race between two operations can still be pushed toward completion or a clean abort, with no central coordinator watching over everything.

This is exactly why the backends behave so differently. HNS on GCS and hierarchical namespace on ADLS Gen2 work because they turn directories into first-class objects owned by a single metadata domain, so the rename never has to cross a shard boundary. S3 Standard's flat key space offers no such locality guarantee. Keys land wherever the hash sends them, full stop.

And this is exactly why S3 Express One Zone can offer RenameObject at all. Directory buckets aren't a feature bolted onto the existing S3 architecture. They're a structurally different namespace model, built from scratch to support the locality rename requires. That's the whole reason the guarantee doesn't extend back to S3 Standard. AWS didn't decline to add it. The old architecture simply has nowhere to hang it.

How Hadoop's S3A committer framework worked around the rename gap before native solutions existed

Hive and Spark jobs run on a standard commit pattern: write output to a temporary location first, then rename that location to the final path once the job finishes, as the signal that the output is complete and safe to read. Simple idea, and it works great on a real filesystem.

On S3 Standard, it falls apart. Apache's documentation is blunt about it: without atomic rename, this final commit step can take longer than the actual analytics job that produced the data, because renaming a large output directory means copying every single file inside it, one at a time.

The fix Hadoop's ecosystem landed on is the S3A Committer framework, and the trick is genuinely clever: skip rename entirely. Tasks upload their output straight to the final destination key using S3's Multipart Upload API, but deliberately hold back the final CompleteMultipartUpload call. The data sits there uploaded but invisible, while the upload ID and ETags get saved off to the side. Only when the job actually commits does the framework go through and call CompleteMultipartUpload for every file. Completing a multipart upload, crucially, is a metadata-only operation inside S3. No copy, no delete, no rename needed anywhere in the chain.

Two variants show up in practice. The Directory Committer buffers task output to local disk, uses HDFS to pass commit information between tasks, and manages conflicts across the entire destination directory. The Partitioned Committer works the same way, except conflict gets managed one partition at a time, which makes it possible to update parts of an existing dataset in place instead of overwriting the whole thing.

What this buys: the core requirement of a Hadoop or Spark job, output that's complete and consistent by the time the job says it's done, gets satisfied without ever asking S3 for a rename it can't provide.

What it doesn't buy is a general rename operation for whatever else the application code needs to do. The committer only covers the commit step at the end of a job. Any other rename issued mid-processing is on its own, and that's a gap teams routinely forget about until it bites them.

Heading into 2025 and 2026, this workaround is still the right call for anything running on S3 Standard, full stop. For teams already on S3 Express One Zone, GCS with HNS, or ADLS Gen2, the native rename guarantees make this entire layer of engineering unnecessary for new pipelines. Building it anyway, out of habit, is wasted effort, so don't.

Why rename semantics become a first-order problem in AI training pipelines specifically

Training data has to move from object storage into GPU memory fast enough to keep expensive accelerators from sitting idle, and storage bottlenecks are a leading cause of GPUs burning money while doing nothing, a figure Hammerspace cited in June 2026. Sounds small until the math lands on what an idle GPU cluster costs per hour.

The scale of the underlying problem runs bigger than most teams expect. MinIO has reported that 57% of enterprises say their data isn't actually AI-ready, even as experimentation with AI keeps accelerating across the board. That's not a model problem, and it's not a compute problem either. It's a storage architecture problem, hiding in plain sight behind every "why is training so slow" ticket.

An IBM infrastructure paper (arXiv:2407.05467) walks through where large-scale training jobs actually stall on I/O. The first bottleneck shows up right when data sitting in object storage needs to reach the GPUs: loading straight from object storage is slow, because typical cloud object storage just doesn't have the IOPS to keep up. And this isn't a one-time cost. It happens again every single time a training job stops and has to restart.

Rename shows up as the quiet hinge in three specific places. Checkpointing is the first: the standard move is to write a checkpoint to a temporary path, then rename it to the canonical path once the write is fully confirmed. That rename is the signal, to every other process and to any restart logic, that the checkpoint is good. Without atomic rename, a partial checkpoint can land at the canonical path and corrupt the next restart, silently, with no error message pointing at the cause.

Dataset staging is the second. Pipelines that move preprocessed batches from a staging prefix into a training prefix use a directory rename as the handoff. If that rename isn't atomic, downstream consumers can read a half-moved batch and never know it.

Coordination across distributed workers is the third. Multiple workers write to temporary paths, then a coordinator renames each one to signal "done." Without atomicity, races appear exactly where a team can least afford them, right at the seam between one training step and the next.

None of this is a hypothetical edge case for ML infrastructure teams. It's the exact mechanism by which rename semantics stop being a storage detail and start being a training-pipeline correctness question. The backend picked, and the specific configuration turned on within it, matters a lot more than it looks like on the pricing page. Finding that out at 3 a.m. during a failed restart is simply the expensive way to learn it.

Filed underPOSIX Semantics

More in POSIX Semantics