Deleting a bucket with versioning deletes all of its files and every version of them. This can't be undone.
How to enable and manage S3 object versioning
Versioning keeps every version of the files in a bucket. When you upload a file with the same name as an existing one, the existing file is kept as an older version instead of being overwritten. When you delete a file, it's hidden, and its versions are kept. You can then download or restore an earlier version, or undo the delete.
Every version takes up storage, so a bucket with versioning grows with each change. To delete older versions automatically after a while, add a lifecycle rule, as described in How to configure lifecycle policies.
This guide walks you through turning on versioning and working with versions using the AWS CLI. It also covers deleting a bucket that has versions, which you can do in the Control Panel too.
Before you start
You need:
- A Managed Object Storage service with a bucket. To create them, see How to get started with UpCloud Managed Object Storage. The examples in this guide use the bucket
site-assets. - The AWS CLI with the
upcloudprofile, as in How to get started with UpCloud Managed Object Storage.
Turn on versioning
aws s3api put-bucket-versioning --bucket <bucket-name> --versioning-configuration Status=Enabled --profile upcloudThe command prints nothing when it succeeds. To check that versioning is on, run:
aws s3api get-bucket-versioning --bucket <bucket-name> --profile upcloud{
"Status": "Enabled"
}For a bucket that has never had versioning turned on, this command prints nothing.
See a file's versions
To see versioning at work, upload a file, change it and upload it again:
echo "Prices, first version" > prices.txt
aws s3 cp prices.txt s3://<bucket-name>/ --profile upcloud
echo "Prices, second version" > prices.txt
aws s3 cp prices.txt s3://<bucket-name>/ --profile upcloudupload: ./prices.txt to s3://site-assets/prices.txt
upload: ./prices.txt to s3://site-assets/prices.txtThe bucket now has both versions of prices.txt. To list them, run:
aws s3api list-object-versions --bucket <bucket-name> --prefix prices.txt --query "Versions[].{VersionId: VersionId, IsLatest: IsLatest, LastModified: LastModified}" --output table --profile upcloud-------------------------------------------------------------------
| ListObjectVersions |
+----------+------------------------------------+-----------------+
| IsLatest | LastModified | VersionId |
+----------+------------------------------------+-----------------+
| True | 2026-10-28T07:18:15.063000+00:00 | 1793171895063 |
| False | 2026-10-28T07:18:14.336000+00:00 | 1793171894336 |
+----------+------------------------------------+-----------------+Each version has its own version ID. The version with True under IsLatest is the current version, which is what you get when you download the file as usual.
Download an older version
To download an older version, give its version ID:
aws s3api get-object --bucket <bucket-name> --key prices.txt --version-id <version-id> prices-old.txt --profile upcloud{
"LastModified": "2026-10-28T07:18:14+00:00",
"ContentLength": 22,
"ETag": "\"c8cc792872e6a98af1bfec53b48154e9\"",
"VersionId": "1793171894336",
"ContentType": "text/plain",
"ServerSideEncryption": "AES256",
"Metadata": {}
}This saves the older version as prices-old.txt. The file in the bucket doesn't change.
Restore an older version
To make an older version current again, copy it over the file. The copy becomes the new current version, and all the other versions are kept.
aws s3api copy-object --bucket <bucket-name> --key prices.txt --copy-source "<bucket-name>/prices.txt?versionId=<version-id>" --profile upcloud{
"CopySourceVersionId": "1793171894336",
"VersionId": "1793171897587",
"ServerSideEncryption": "AES256",
"CopyObjectResult": {
"ETag": "\"c8cc792872e6a98af1bfec53b48154e9\"",
"LastModified": "2026-10-28T07:18:17.587000+00:00"
}
}Undo a delete
When you delete a file in a bucket with versioning, the delete adds a delete marker. The marker hides the file, so it's no longer listed, but all of its versions are kept:
aws s3 rm s3://<bucket-name>/prices.txt --profile upclouddelete: s3://site-assets/prices.txtTo bring the file back, delete the delete marker. First, find the marker's version ID:
aws s3api list-object-versions --bucket <bucket-name> --prefix prices.txt --query "DeleteMarkers[].{VersionId: VersionId, IsLatest: IsLatest}" --output table --profile upcloud-------------------------------
| ListObjectVersions |
+-----------+-----------------+
| IsLatest | VersionId |
+-----------+-----------------+
| True | 1793171898921 |
+-----------+-----------------+Then delete the marker by its version ID:
aws s3api delete-object --bucket <bucket-name> --key prices.txt --version-id <marker-version-id> --profile upcloud{
"DeleteMarker": true,
"VersionId": "1793171898921"
}The file is listed again, with the version it had before the delete.
Delete a version permanently
To delete one version for good, delete it by its version ID. This can't be undone.
aws s3api delete-object --bucket <bucket-name> --key prices.txt --version-id <version-id> --profile upcloud{
"VersionId": "1793171894336"
}To delete several versions, run the command once for each version ID.
Delete a file and all its versions
To remove a file completely, delete all of its versions and delete markers. On Linux or macOS, this loop does it. Set BUCKET to the bucket's name and KEY to the file's name first:
BUCKET=<bucket-name>
KEY=prices.txt
aws s3api list-object-versions --bucket "$BUCKET" --prefix "$KEY" --output text --profile upcloud \
--query "[Versions, DeleteMarkers][] | [?Key=='$KEY'].[VersionId]" |
while read -r version; do
aws s3api delete-object --bucket "$BUCKET" --key "$KEY" --version-id "$version" --profile upcloud > /dev/null
doneThe loop prints nothing. It deletes only the file named in KEY, so other files whose names start the same way, such as prices.txt.bak, are kept. The deleted versions can't be restored.
To keep the current version and delete only the older ones, use this --query line in the loop instead:
--query "Versions[?Key=='$KEY' && IsLatest==\`false\`].[VersionId]" |To delete older versions automatically, add a lifecycle rule, as described in How to configure lifecycle policies.
Suspend versioning
Once a bucket has had versioning turned on, versioning can't be turned off completely. To stop keeping new versions, suspend it instead:
aws s3api put-bucket-versioning --bucket <bucket-name> --versioning-configuration Status=Suspended --profile upcloudThe versions that already exist are kept. From then on, each upload replaces the file's current version, which has the version ID null. To keep new versions again, turn versioning back on with Status=Enabled.
Delete a bucket with versioning
Deleting all the files with aws s3 rm --recursive doesn't empty a bucket with versioning. It adds a delete marker for each file, and all their versions are kept. Deleting the bucket with aws s3 rb then fails:
remove_bucket failed: s3://site-assets An error occurred (BucketNotEmpty) when calling the DeleteBucket operation: The bucket you tried to delete is not empty.To delete the bucket, delete it in the Control Panel, or delete every version with the AWS CLI first.
- Go to Object Storage, open the service and go to its Buckets tab.
- On the bucket's row, click Delete.
- Type the bucket's name under Bucket name and click Delete.
The service's status changes while it deletes the bucket with all its files and versions. When it's done, the status shows Running again.
Next steps
- How to configure lifecycle policies explains how to delete older versions automatically.
- How to perform basic Object Storage operations using AWS CLI shows more commands for working with buckets and files.