Back

Blog details

What Is S3 Object Versioning and How Does It Work?

AIOZ Network
7 min readSeptember 09, 2026
aioz-storage
AIOZ Storage cover: What Is Object Versioning?

S3 object versioning keeps every version of an object in its bucket, each with its own version ID, so an overwrite or delete never destroys the earlier copy. AWS says the point is to "restore objects that are accidentally deleted or overwritten." It is off until you turn it on.

TL;DR:

  • Versioning is off by default. Once you enable it, an overwrite turns the old copy into a "noncurrent" version that sits next to the new "current" one.
  • A delete without a version ID removes nothing. S3 adds a delete marker, GET returns 404, and every version stays recoverable underneath.
  • Each version is billed as a complete object, not a diff, which is why NoncurrentVersionExpiration lifecycle rules exist.
  • A bucket can't go back to unversioned, only to suspended. AIOZ Storage doesn't offer versioning today, so a new upload to the same key replaces the old one.

Updated Oct 28, 2026: definition-first opening, question headings, a labelled diagram, CLI commands to enable versioning and restore old versions, lifecycle limits, and a section on AIOZ Storage overwrites.

What Is S3 Object Versioning?

AWS describes S3 Versioning as a way to "keep multiple versions of an object in one bucket so that you can restore objects that are accidentally deleted or overwritten." S3 gives each stored version a unique version ID, and two versions can share the same key while staying separately retrievable.

A bucket is always in one of three states: unversioned (the default), versioning-enabled or versioning-suspended. The state applies to every object in the bucket, never to some of them. One rule catches people out: once you enable versioning, AWS says the bucket "can never return to an unversioned state." You can suspend it, which stops new versions from piling up, but the versions you already have stay where they are.

How Does S3 Versioning Work on Overwrite?

In a versioned bucket, an overwrite doesn't overwrite anything. AWS's documentation is specific: "if you overwrite an object, Amazon S3 adds a new object version in the bucket. The previous version remains in the bucket and becomes a noncurrent version." The bucket now holds two full copies under one key: a plain GET returns the current one, and you can fetch the older one by passing its version ID.

Objects that were in the bucket before you enabled versioning keep a version ID of null. Enabling versioning doesn't change them; it changes how S3 handles the next write to each key.

What Happens When You Delete an Object in a Versioned Bucket?

A normal delete doesn't erase data either. In AWS's words, "if you delete an object, instead of removing the object permanently, Amazon S3 inserts a delete marker, which becomes the current object version." A GET on that key now returns a 404 with the header x-amz-delete-marker: true, so the object looks gone to every ordinary request even though every earlier version is still in the bucket.

Permanent deletion is a separate, deliberate request. AWS notes that "you can permanently delete an object by specifying the version that you want to delete," and S3 doesn't insert a delete marker for that request. To undelete an object, you delete the delete marker itself, and the newest real version becomes current again. If you send another plain delete while a marker is current, S3 doesn't remove the marker; it adds a second one.

Diagram of one S3 key across four requests in a versioned bucket: two PUTs create versions 111111 and 121212, a simple DELETE adds a delete marker and GET returns 404, deleting the marker makes 121212 current again
One key, four requests. Version IDs follow AWS's own photo.gif example.

Enabling Versioning and Restoring an Old Version

You turn versioning on per bucket. AWS's CLI example:

aws s3api put-bucket-versioning --bucket amzn-s3-demo-bucket1 --versioning-configuration Status=Enabled

AWS warns that the first time you enable versioning, the change can take up to 15 minutes to spread. It recommends waiting that long before you send writes or deletes. To see every version and delete marker in a bucket, list them:

aws s3api list-object-versions --bucket amzn-s3-demo-bucket1

There are two ways to restore an older version. You can copy it over the same key, which creates a new current version with the old content and keeps every existing version:

aws s3api copy-object \
  --bucket amzn-s3-demo-bucket \
  --key my-object.jpg \
  --copy-source amzn-s3-demo-bucket/my-object.jpg?versionId=previous-version-id

Or you can permanently delete the current version, which makes the previous one current. That second route destroys data, so the copy is the safer default when you're not sure.

Version IDs, Null IDs and MFA Delete

AWS describes version IDs as "Unicode, UTF-8 encoded, URL-ready, opaque strings" that "cannot be edited." In AWS's own example, photo.gif version 111111 and photo.gif version 121212 are two different objects under one name. Your application should store the ID S3 returns rather than try to predict it.

If a stolen credential shouldn't be able to wipe your history, AWS offers MFA Delete. With it, "the bucket owner must include two forms of authentication in any request to delete a version or change the versioning state of the bucket." Only the bucket owner's root account can enable it, and you can't do that from the console; you need the AWS CLI or an SDK:

aws s3api put-bucket-versioning --bucket amzn-s3-demo-bucket1 --versioning-configuration Status=Enabled,MFADelete=Enabled --mfa "SerialNumber 123456"

The Storage Cost of Keeping Every Version

Versioning's protection isn't free, and AWS is upfront about it: "Normal Amazon S3 rates apply for every version of an object that is stored and transferred. Each version of an object is the entire object; it is not a diff from the previous version." Three versions of a 1 GB file means paying for 3 GB, not 1 GB plus two small deltas. In a bucket where your application rewrites the same keys every day and nothing cleans up, that bill keeps growing.

Expiring Old Versions With Lifecycle Rules

The fix is a lifecycle rule built for it: NoncurrentVersionExpiration. AWS's API reference says it "specifies when noncurrent object versions expire," and that "upon expiration, Amazon S3 permanently deletes the noncurrent object versions." It takes two settings:

  • NoncurrentDays: how many days a version must be noncurrent before S3 can act on it.
  • NewerNoncurrentVersions: how many noncurrent versions to keep, up to 100.

When you set both, S3 deletes a version only after both values are exceeded. AWS's example rule keeps the 5 newest noncurrent versions and expires older ones after 365 days:

<NoncurrentVersionExpiration>
  <NewerNoncurrentVersions>5</NewerNoncurrentVersions>
  <NoncurrentDays>365</NoncurrentDays>
</NoncurrentVersionExpiration>

Expiring versions can leave a key with nothing but a delete marker. AWS calls that an expired object delete marker, and a lifecycle rule can clean those up too. With both rules in place, recent history stays recoverable and old history ages out instead of billing forever.

Why Object Lock Depends on Versioning

S3 Object Lock, the WORM feature, is built on versioning. Enabling Object Lock turns versioning on automatically, because a lock protects one specific version from deletion or overwrite. Once you understand versioning, object lock reads as a small extension of it: compliance mode simply stops anyone, even the root user, from deleting a locked version before its date.

How AIOZ Storage Handles It

AIOZ Storage doesn't offer object versioning today, so it also has no object lock. When you upload to a key that already exists, the new object replaces the old one. AIOZ Storage protects each object with Reed-Solomon erasure coding across nodes, which keeps it available when nodes fail. That doesn't bring back a version you or your code overwrote.

If you need history, keep it in the key name. The AIOZ CLI guide's copy command can save the current object under a dated key before you overwrite it:

aws s3 --endpoint-url https://s3.aiozstorage.network cp s3://bucket-name/report.csv s3://bucket-name/archive/2026-10-28/report.csv

When you then upload the new file with the AWS CLI, set AWS_REQUEST_CHECKSUM_CALCULATION=when_required and path-style addressing. AIOZ Storage needs a Content-Length on uploads and doesn't resolve bucket subdomains, and current AWS SDK defaults send chunked uploads that the endpoint rejects (tested with boto3 on Oct 19, 2026).

What the docs don't cover yet (all concept, tutorial and SDK pages read Oct 28, 2026):

  • Object versioning, version IDs, delete markers or MFA Delete
  • Lifecycle rules, including NoncurrentVersionExpiration
  • Object lock

For the full list of object commands AIOZ supports, see the AIOZ Storage CLI guide.

Frequently Asked Questions

What is S3 object versioning?
A bucket setting that keeps every version of an object when it's overwritten or deleted, each with its own version ID, so you can restore an earlier copy. It's off by default.

What happens when you delete an object in a versioned bucket?
S3 adds a delete marker as the current version, and a plain GET returns 404. Every earlier version stays in the bucket and you can still retrieve it by version ID.

How do you restore a deleted object in S3?
Delete the delete marker. The newest real version becomes current again. To restore an older version instead, copy it over the same key with copy-object and its version ID.

How do you permanently delete a specific version?
Send a delete request that names that version's ID. S3 removes that version and doesn't add a delete marker.

Can you turn off S3 versioning?
Not completely. A bucket that has had versioning enabled can only be suspended, never returned to unversioned, and suspending keeps the versions you already have.

Does keeping multiple versions cost more?
Yes. AWS bills each version as a complete object, so three versions of a file cost three full copies until a lifecycle rule expires the old ones.

Does AIOZ Storage support object versioning?
No. AIOZ Storage doesn't offer versioning as of Oct 28, 2026, so uploading to an existing key replaces it. Keep history by writing older copies under dated keys.

References

We only send updates when meaningful changes ship, and you can unsubscribe anytime

Related Content

blog thumbnail

What Is Distributed Storage? How It Works, With Examples

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.

aioz-storage
6 min readNovember 03, 2026
blog thumbnail

What Are Egress Fees? How Download Charges Work in Storage

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.

aioz-storage
6 min readOctober 30, 2026
blog thumbnail

Object Storage Vector Database: Where AIOZ Storage Fits

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
10 min readOctober 27, 2026
blog thumbnail

AIOZ Storage Vector Database Pricing: What You Pay For

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

aioz-storage
5 min readOctober 23, 2026
blog thumbnail

How to Create a Bucket and Upload a File on AIOZ Storage

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.

aioz-storage
5 min readOctober 20, 2026
blog thumbnail

AIOZ Storage Rate Limit: Working Within 100 Requests/s

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.

aioz-storage
7 min readOctober 16, 2026