Delete objects on a schedule with lifecycle rules
Delete objects some days after upload or from a date, remove old versions and delete markers, and abort unfinished uploads, once a day.
In the dashboard
A lifecycle rule deletes what you no longer need from a bucket on a schedule. A rule can delete objects a number of days after upload or from a date, delete old versions, remove delete markers that have nothing left behind them, and abort multipart uploads that never finished. Use rules to keep logs for 30 days, to clear out temporary uploads, or to stop old versions from adding to your bill.
You manage rules in the bucket's Lifecycle tab or with the API. S3 clients can read the rules and cannot change them.
Before you begin
Section titled Before you begin- Sign in to the dashboard and open the service. The service must be
activeto change rules. While it waits for payment or is suspended, you can read them, and they keep running. - Know whether the bucket keeps versions. A rule that deletes objects works differently on a bucket with versioning on (Rules on a bucket that keeps versions).
Warning
On a bucket without versioning, a rule deletes objects for good, with no undo. Try a new rule on a test bucket, or with a Prefix that only a few objects match, before you point it at data you need.
How rules run
Section titled How rules run- Rules run once a day, and all times are in UTC.
- An object's days count from when it was uploaded: its last modified time. Writing an object again starts its days over.
- An object is due at the first midnight UTC after its upload time plus the rule's days, as in Amazon S3. An object uploaded at 15:00 UTC on Sep 1 under a 30 day rule is due at midnight UTC on Oct 2.
- The daily run deletes what is due, so an object can stay up to a day past its time. Until it goes, an object is still listed, readable and billed.
- Each run spends a limited time on each bucket and checks at most 100,000 objects in it. A larger bucket takes more than one run to check in full, and each run carries on where the last one stopped, so its objects can stay longer past their time.
- When several rules match an object, the first rule that makes it due deletes it. A rule that is turned off does nothing.
- Deletes made by a rule are free. Data a rule deletes for good stops counting towards your stored data at the next hourly measurement (Usage and billing).
- Each object a rule removes sends an event to the bucket's event notification rules (Events).
- A version that Object Lock protects, by a retention period or a legal hold, stays until the protection ends. Each run reports it as not deleted.
The default rule
Section titled The default ruleEvery new bucket starts with one rule, abort-incomplete-uploads. It aborts multipart uploads still unfinished 7 days after they started, so the parts of a failed upload do not stay in the bucket. The list marks it Default. You can change it, turn it off or delete it like any other rule.
Buckets created before lifecycle rules existed have no rules until you add one.
Add a rule
Section titled Add a rule- Open the service, select the Buckets tab, then select the bucket.
- Select the Lifecycle tab. The Lifecycle rules card lists the bucket's rules.
- Select Add rule…. The dialog starts with a rule that deletes objects 30 days after upload.
- Under Which objects, say which objects the rule applies to. Leave every field blank to apply it to every object.
- Prefix: only keys that start with this, such as
logs/. - Tags: only objects with every tag listed, one per line as
key=value, such astemporary=yes. - Larger than and Smaller than, with the size in Unit: only objects in that range.
- Prefix: only keys that start with this, such as
- Under What it does, choose at least one action:
- Delete objects: choose After a number of days and type the Days after upload, or choose On a date and pick the Date (UTC). A date rule deletes every object that matches from midnight UTC on that date, including objects uploaded later.
- Delete old versions: type the Days after they are replaced. To keep a few old versions whatever their age, type how many in Keep the newest, from 1 to 100.
- Remove delete markers left with no versions.
- Abort unfinished uploads: type the Days after they start.
- Optionally, give the rule a Rule ID. A blank ID becomes
rule-1,rule-2and so on. - To save the rule without running it yet, untick Apply this rule.
- Select Add rule.
A message confirms it: Lifecycle rule added. It runs from the next daily run.
Some actions cannot share a rule, and the dialog greys them out with the reason:
- Remove delete markers left with no versions cannot share a rule that deletes objects or filters by tag.
- Abort unfinished uploads works with a Prefix only, without tags or sizes.
Add either one as a rule of its own.
Result
Section titled ResultThe rule appears on the Lifecycle rules card:
- Rule
- The rule's ID. Off marks a rule that is turned off, and Default the rule the bucket started with.
- Applies to
- Which objects it picks, such as
Every object,Keys starting with logs/orTagged temporary=yes. - Does
- What it does to them, such as
Delete objects 30 days after uploadorAbort unfinished uploads after 7 days.
The next daily run applies it, and the Recent runs card shows what it removed.
Rules on a bucket that keeps versions
Section titled Rules on a bucket that keeps versionsWhen a bucket's versioning is on or suspended, deleting an object keeps its data as an old version, as a delete from an S3 client does:
- Delete objects adds a delete marker. The object leaves listings, and its data stays as an old version, still billed. Add Delete old versions to remove that data later. While versioning is on, the dialog reminds you of this.
- Delete old versions counts an old version's days from when a newer version or a delete marker replaced it. Keep the newest keeps that many of each key's old versions whatever their age; delete markers do not count among them.
- Remove delete markers left with no versions removes a delete marker once it is the only thing left of its key. Use it with Delete old versions, which leaves such markers behind.
On a bucket that has never had versioning, the old version actions do nothing, and the dialog says so.
Read the run history
Section titled Read the run historyThe Recent runs card lists the latest 10 runs on the bucket, newest first:
- Started
- When the run reached the bucket.
- Removed
- How many objects, old versions and delete markers it removed.
- Freed
- How much data it deleted for good. A delete marker that hides an object frees nothing.
- Uploads aborted
- How many unfinished uploads it aborted.
- Result
- Finished when it checked the whole bucket. Continues next run when it reached its limit first, and the next run carries on from there. Not finished with the reason when something could not be deleted, such as
3 objects could not be deleted. The next run tries again.Running while it is still going.
What a run could not delete is still due, and the next run tries again.
Change, turn off or delete a rule
Section titled Change, turn off or delete a ruleEach rule's menu has:
- Edit rule…, which opens the same fields as Add rule…. Select Save rule to keep the change.
- Turn off or Turn on. A rule that is turned off stays on the list and does nothing.
- Delete rule…, which asks you to confirm with Delete rule.
To remove every rule, open the menu at the top right of the Lifecycle rules card, select Remove every rule… and confirm with Remove rules. Objects and unfinished uploads then stay until you delete them.
Read the rules with an S3 client
Section titled Read the rules with an S3 clientAny access key whose scope covers the bucket can read its lifecycle rules, read only keys included. With the AWS CLI:
aws s3api get-bucket-lifecycle-configuration --bucket u7-assets \
--endpoint-url https://s3.fra.coritan.com:7337
{
"Rules": [
{
"ID": "abort-incomplete-uploads",
"Status": "Enabled",
"Filter": {"Prefix": ""},
"AbortIncompleteMultipartUpload": {"DaysAfterInitiation": 7}
},
{
"ID": "logs",
"Status": "Enabled",
"Filter": {"Prefix": "logs/"},
"Expiration": {"Days": 30}
}
]
}
A bucket with no rules answers NoSuchLifecycleConfiguration. Each read is a Class B request.
PutBucketLifecycleConfiguration and DeleteBucketLifecycle answer 403 AccessDenied with every access key. Change the rules in the dashboard or with the API (With the API).
Rules can only delete. There is one storage class, so S3's transitions to another class are refused.
Troubleshooting
Section titled Troubleshooting- An object is still there after its day
- The daily run deletes what is due, so an object can stay up to a day past its time (How rules run). In a large bucket, Recent runs may say Continues next run. Check also that the rule is not Off, and that its prefix and tags match the object exactly. On a bucket that keeps versions, Delete objects keeps the data as an old version until Delete old versions removes it.
Lifecycle rules here delete objects and abort unfinished uploads. There is one storage class, so a rule cannot move objects to another.- The rules sent include a transition. Remove it.
Two lifecycle rules are named logs. Each rule needs its own ID.- Give one of the rules another Rule ID.
Lifecycle rule 1: delete objects after a number of days or on a date, but pick one- A rule sent through the API holds both
expiration_daysandexpiration_date. Keep one. Lifecycle rule 1: removing expired delete markers cannot share a rule with deleting objects after days or on a date- Put the delete marker action in a rule of its own.
Lifecycle rule 1: to keep a number of old versions, also say after how many days the rest are deleted- Fill in Days after they are replaced as well as Keep the newest.
Lifecycle rule 1: aborting unfinished uploads can filter by prefix only- Remove the tags and sizes, or put the abort action in a rule of its own.
Lifecycle rule 1: the smallest size must be below the largest- Larger than must be less than Smaller than.
A bucket can have at most 100 lifecycle rules- Merge rules that do the same thing, or use a shorter prefix that covers several.
This service is suspended; it can be changed once it is active- Pay the overdue invoice (Failed payments and suspended services), then try again. The rules keep running meanwhile.
Too many requests for this action. Try again later.- Your account made 60 CORS and lifecycle rule changes in the last hour. Wait, then try again.
The bucket would not take these lifecycle rules. Try again in a minute.- The bucket's region could not save the rules, and nothing changed. Try again. If it keeps happening, contact support with the whole message.
Related
Section titled Related- Upload, download and delete objects
- Get notified when objects change
- Usage and billing
- Let websites use a bucket with CORS rules
With the API
Section titled With the APIEach request takes the service ID and the bucket ID, from GET /api/v1/client/object-storage/{service_id}/buckets. A service that is not Object Storage on your account answers 404 with Object storage service not found, and a bucket that is not on the service answers 404 with Bucket not found.
Read the rules
Section titled Read the rulesGET /api/v1/client/object-storage/{service_id}/buckets/{bucket_id}/lifecycle returns the bucket's rules:
curl https://api.coritan.com/api/v1/client/object-storage/1207/buckets/31/lifecycle \
-H "Authorization: Bearer $CORITAN_TOKEN"
{
"bucket_id": 31,
"rules": [
{
"id": "abort-incomplete-uploads",
"enabled": true,
"prefix": "",
"tags": [],
"object_size_greater_than": null,
"object_size_less_than": null,
"expiration_days": null,
"expiration_date": null,
"expired_object_delete_marker": false,
"noncurrent_days": null,
"newer_noncurrent_versions": null,
"abort_incomplete_multipart_days": 7
}
],
"max_rules": 100,
"default_rule_id": "abort-incomplete-uploads"
}
default_rule_id is the ID of the rule new buckets start with.
Replace the rules
Section titled Replace the rulesPUT /api/v1/client/object-storage/{service_id}/buckets/{bucket_id}/lifecycle replaces every rule with the list you send. Send the default rule too if you want to keep it:
curl -X PUT https://api.coritan.com/api/v1/client/object-storage/1207/buckets/31/lifecycle \
-H "Authorization: Bearer $CORITAN_TOKEN" \
-H "Content-Type: application/json" \
-d '{"rules": [{"id": "abort-incomplete-uploads", "abort_incomplete_multipart_days": 7}, {"id": "logs", "prefix": "logs/", "expiration_days": 30}, {"id": "old-versions", "noncurrent_days": 14, "newer_noncurrent_versions": 3}]}'
It answers 200 with the rules as saved, every field filled in as above. The fields:
id- Up to 255 characters, unique in the bucket. A blank ID becomes
rule-1,rule-2and so on. enabledfalsekeeps the rule without running it. The default istrue.prefix,tags,object_size_greater_than,object_size_less_than- Which objects the rule picks: keys starting with the prefix, objects with every tag (up to 10, each
{"key": "...", "value": "..."}), and sizes in bytes. Leave them out for every object. expiration_daysorexpiration_date- Delete objects this many days after upload, or from this date (
YYYY-MM-DD) at midnight UTC. Not both. noncurrent_daysandnewer_noncurrent_versions- Delete old versions this many days after they were replaced.
newer_noncurrent_versionsis optional, and keeps the newest 1–100 of each key's old versions whatever their age. expired_object_delete_markertrueremoves a delete marker once it is the only version of its key left.abort_incomplete_multipart_days- Abort multipart uploads still unfinished this many days after they started.
Each rule needs at least one action. An empty rules list removes every rule.
Remove every rule
Section titled Remove every ruleDELETE /api/v1/client/object-storage/{service_id}/buckets/{bucket_id}/lifecycle removes every rule, the default one included, and answers with an empty rules list:
curl -X DELETE https://api.coritan.com/api/v1/client/object-storage/1207/buckets/31/lifecycle \
-H "Authorization: Bearer $CORITAN_TOKEN"
List the runs
Section titled List the runsGET /api/v1/client/object-storage/{service_id}/buckets/{bucket_id}/lifecycle/runs lists the latest runs on the bucket, newest first. limit takes 1–100 and defaults to 20:
curl "https://api.coritan.com/api/v1/client/object-storage/1207/buckets/31/lifecycle/runs?limit=2" \
-H "Authorization: Bearer $CORITAN_TOKEN"
{
"items": [
{
"id": 9120,
"started_at": "2026-10-08T04:30:12",
"finished_at": "2026-10-08T04:31:40",
"removed_objects": 1284,
"removed_bytes": 48318382080,
"aborted_uploads": 2,
"complete": true,
"error": null
},
{
"id": 9031,
"started_at": "2026-10-07T04:30:09",
"finished_at": "2026-10-07T04:35:09",
"removed_objects": 310,
"removed_bytes": 1073741824,
"aborted_uploads": 0,
"complete": false,
"error": null
}
],
"total": 41
}
finished_at is null while the run is going. complete is false when the run stopped before the end of the bucket, and the next run carries on from there. error says what could not be deleted, and the next run tries again. Times are in UTC.
Errors
Section titled Errors| Status | detail |
Cause |
|---|---|---|
409 |
This service is pending; it can be changed once it is active |
The service is not active. The message names its status. |
422 |
A message that names the rule, such as Lifecycle rule 2: the smallest size must be below the largest |
A rule breaks the rules above. Troubleshooting lists the common ones. |
422 |
A list of fields | The body is not in the shape above, or limit is out of range. |
429 |
An object with "error": "rate_limited" and retry_after_seconds |
Your account made 60 CORS and lifecycle rule changes in the last hour. The Retry-After header says how long to wait. |
502 |
The bucket would not take these lifecycle rules. Try again in a minute. |
The bucket's region refused the rules. Nothing changed. |
API operations on this page
| Method | Path | What it does |
|---|---|---|
GET | /api/v1/client/object-storage/{service_id}/buckets/{bucket_id}/lifecycle | The bucket's lifecycle rules: what we delete from it, and when |
PUT | /api/v1/client/object-storage/{service_id}/buckets/{bucket_id}/lifecycle | Replace the bucket's lifecycle rules with the ones sent, at most 100 |
DELETE | /api/v1/client/object-storage/{service_id}/buckets/{bucket_id}/lifecycle | Remove every lifecycle rule from the bucket, the default one included |
GET | /api/v1/client/object-storage/{service_id}/buckets/{bucket_id}/lifecycle/runs | List lifecycle runs |