
Strong consistency means a read right after a write always returns the new data, while eventual consistency allows a short window where that read can still return old data. Amazon S3 used eventual consistency until December 1, 2020, and has been strongly consistent since.
TL;DR:
Updated Oct 19, 2026: answer-first opening, question sections, a tighter history, a read-after-write test pointed at AIOZ Storage's endpoint, a list of what our docs don't cover yet, the AIOZ section now names its Reed-Solomon erasure coding, and the test client has the upload settings AIOZ Storage needs.
A consistency model answers one question: after data changes, when is every reader guaranteed to see the change? Strong consistency says immediately, every time, while eventual consistency says once the change has propagated, which leaves a window where a read can return stale data even though the write already succeeded.
Neither model is a bug, because making every read, from anywhere, reflect every write at once is a harder distributed-systems problem than allowing a short propagation delay. Eventual consistency trades that guarantee for simpler replication, and your application pays the difference in defensive code.
Not anymore, although S3 "pioneered object storage in the cloud... with eventual consistency," in AWS's words, and kept that model for its first fourteen years. Under it, a successful write was stored durably, but a GET right afterwards could return an old version or, for a brand-new key, nothing at all. A listing taken moments after a write could miss the new object.
That gap forced real work onto developers. AWS's announcement says teams had to "insert custom code into these applications, or provision databases" to keep objects consistent with changes in S3. Big data and analytics jobs, which AWS says need "access to an object immediately after a write," were hit hardest.
On December 1, 2020, AWS announced that "Amazon S3 now delivers strong read-after-write consistency automatically for all applications." Nobody had to opt in or change code, and AWS says it came "without changes to performance or availability" and "at no additional cost." Every existing bucket got the stronger guarantee on the same day.
AWS states that "after a successful write of a new object, or an overwrite or delete of an existing object, any subsequent read request immediately receives the latest version of the object." The guarantee covers "all S3 GET, PUT, and LIST operations, as well as operations that change object tags, ACLs, or metadata," in every region. Listings changed too, so you can now "immediately perform a listing of the objects in a bucket with any changes reflected."
"Strongly consistent" is easy to over-read, and AWS's consistency documentation is clear about three limits once more than one client touches the same data.
Concurrent writes are last-writer-wins. AWS states that "Amazon S3 does not support object locking for concurrent writers. If two PUT requests are simultaneously made to the same key, the request with the latest timestamp wins." A read that starts before the second write finishes can return either value. Because network latency can reorder acknowledgments, AWS advises reading after both writes are acknowledged to learn the final value.
Single keys are atomic, but there is no atomicity across keys. A GET during a PUT returns "either the old data or the new data, but never partial or corrupt data." That protects one object, but not a data file and its index that must change together. AWS says "there is no way to make atomic updates across keys" unless you build it into your application.
Bucket configuration is still eventually consistent. A deleted bucket can briefly appear in a bucket list. After you first enable versioning, AWS recommends waiting 15 minutes before writing or deleting objects in that bucket, which matters if your setup script runs both steps back to back.
Since S3 won't lock a key for you, the fix for lost updates is a conditional write. If-None-Match: * makes a write succeed only if the key doesn't exist yet, which guards against accidental overwrites. If-Match: <etag> makes it succeed only if the current ETag matches the one you send, the compare-and-swap pattern of read, note the ETag, and write back only if nothing changed.
# create-only: fails if the key already exists
aws s3api put-object --bucket my-bucket --key config/state.json \
--body state.json --if-none-match "*"
# update only if the object is unchanged since you read it
aws s3api put-object --bucket my-bucket --key config/state.json \
--body state.json --if-match "6805f2cfc46c0f04559748bb039d69ae"Per AWS, both headers work with PutObject, CompleteMultipartUpload and CopyObject, and the requests must be signed with Signature Version 4. Know the failure codes before you write retry logic:
| Situation | Response |
|---|---|
If-None-Match and the key already exists | 412 Precondition Failed |
If-Match and the ETag doesn't match | 412 Precondition Failed |
| Several conditional writes race for the same key | The first to finish succeeds, the rest get 412 |
| A delete finishes before the conditional write | 409 Conflict (If-None-Match) or 404 Not Found (If-Match) |
Conditional writes ignore multipart uploads that are still in progress. If another client writes the key while your upload is open, your conditional CompleteMultipartUpload fails with 412, and after a 409 you have to start the multipart upload again. Because these checks compare ETags, read what an ETag really is before you compare values by hand.
AIOZ Storage runs on AIOZ DePIN and stores each object as Reed-Solomon erasure-coded pieces on different nodes, per AIOZ Storage engineering (2026). When a new write to those pieces becomes readable everywhere is exactly what a consistency model describes, and our docs don't say which one applies. You can see one hint in the official Python SDK sample: it calls bucket.wait_until_exists() after the upload, a boto3 waiter that polls until the object shows up. That pattern is safe under either model, so it tells you nothing about which one applies.
The way to find out is a test against your own bucket. The loop below covers the core cases: overwrite then read, write then list, and delete then list. We have not run it against AIOZ Storage yet, so record what you see:
import os
import uuid
import boto3
from botocore.config import Config
s3 = boto3.client(
"s3",
region_name="us-east-1",
endpoint_url="https://s3.aiozstorage.network",
aws_access_key_id=os.environ["ACCESS_KEY"],
aws_secret_access_key=os.environ["SECRET_KEY"],
config=Config(
request_checksum_calculation="when_required",
response_checksum_validation="when_required",
s3={"addressing_style": "path"},
),
)
bucket = "my-test-bucket"
failures = 0
for i in range(200):
key = f"consistency-test/{uuid.uuid4()}"
s3.put_object(Bucket=bucket, Key=key, Body=b"v1")
s3.put_object(Bucket=bucket, Key=key, Body=b"v2") # overwrite
if s3.get_object(Bucket=bucket, Key=key)["Body"].read() != b"v2":
failures += 1 # stale read
listed = s3.list_objects_v2(Bucket=bucket, Prefix=key).get("KeyCount", 0)
if listed != 1:
failures += 1 # write missing from listing
s3.delete_object(Bucket=bucket, Key=key)
if s3.list_objects_v2(Bucket=bucket, Prefix=key).get("KeyCount", 0) != 0:
failures += 1 # deleted key still listed
print("anomalies:", failures)The Config block matters on AIOZ Storage. Current boto3 versions send uploads as aws-chunked streams and address buckets by subdomain, and the endpoint needs a Content-Length on uploads and path-style URLs (checked Oct 19, 2026).
Each pass sends six requests one after another, so a single client stays well under the documented 100 requests per second limit. Zero anomalies over a few hundred passes from one client doesn't prove strong consistency, because rare gaps and multi-client races won't always show. A nonzero count is a real finding, and it is the evidence you want before building a pipeline that assumes read-after-write.
What the docs don't cover yet:
If-None-Match and If-Match are supported.For the client setup used above, see the AIOZ Storage Python SDK guide.
When did S3 switch to strong consistency?
On December 1, 2020, when AWS made strong read-after-write consistency automatic for all applications, with no code changes and no extra cost.
Did applications need to change anything to get it?
No, AWS applied it to every existing bucket "without changes to performance or availability," so old retry loops still work but are no longer needed.
What happens if two clients write to the same S3 key at the same time?
The request with the latest timestamp wins, because S3 doesn't lock objects for concurrent writers, so read after both writes are acknowledged to learn the final value.
How do I stop an S3 write from overwriting an existing object?
Send If-None-Match: * with the write, and it fails with 412 Precondition Failed if the key already exists.
Can I update several S3 objects atomically?
No, updates are atomic per key only, and AWS says there is no way to make atomic updates across keys unless your application builds it.
Does AIOZ Storage guarantee strong read-after-write consistency?
Our docs don't state a consistency model yet, so run the read-after-write test above on your own bucket before you depend on it.

Distributed storage keeps data on many independent nodes that act as one system. See how it works, replication vs erasure coding, its types and trade-offs.

Egress fees are charges for data leaving a storage provider's network. See what triggers them, how to estimate them, and what AIOZ Storage's docs say.

An object storage vector database keeps vectors in the storage layer, not a cluster. See how it differs, when to pick it, and where AIOZ Storage fits in.

AIOZ Storage vector database pricing line by line: upload, storage, queries, data searched and data returned, with a worked monthly example you can reuse.

Create a bucket and upload a file on AIOZ Storage in five steps: sign up, set a passphrase, add credits, and upload. Plus what the passphrase cannot recover.

The AIOZ Storage rate limit is 100 requests per second. See what the docs do and don't say, and how to stay under it with boto3 retries and a limiter.