{"slug":"object-storage-lifecycle","title":"Lifecycle Rules Guide","description":"Automatically expire and delete objects based on age or prefix to manage storage costs and enforce data retention policies.","section":null,"url":"https://docs.danubedata.ro/object-storage-lifecycle","markdown_url":"https://docs.danubedata.ro/object-storage-lifecycle.md","breadcrumbs":[],"headings":[{"level":1,"title":"Lifecycle Rules Guide","id":"lifecycle-rules-guide"},{"level":2,"title":"Overview","id":"overview"},{"level":3,"title":"How It Works","id":"how-it-works"},{"level":2,"title":"Configuring Lifecycle Rules via Dashboard","id":"configuring-lifecycle-rules-via-dashboard"},{"level":2,"title":"Configuring via API","id":"configuring-via-api"},{"level":3,"title":"Create or Update Lifecycle Rules","id":"create-or-update-lifecycle-rules"},{"level":3,"title":"Remove All Lifecycle Rules","id":"remove-all-lifecycle-rules"},{"level":2,"title":"Configuring via AWS CLI","id":"configuring-via-aws-cli"},{"level":3,"title":"Set Lifecycle Rules","id":"set-lifecycle-rules"},{"level":3,"title":"View Current Rules","id":"view-current-rules"},{"level":3,"title":"Remove All Rules","id":"remove-all-rules"},{"level":2,"title":"Configuring via S3 SDKs","id":"configuring-via-s3-sdks"},{"level":3,"title":"Python (boto3)","id":"python-boto3"},{"level":3,"title":"Node.js (AWS SDK v3)","id":"nodejs-aws-sdk-v3"},{"level":3,"title":"PHP (Laravel)","id":"php-laravel"},{"level":2,"title":"Rule Configuration Reference","id":"rule-configuration-reference"},{"level":3,"title":"Required Fields","id":"required-fields"},{"level":3,"title":"Expiration Options","id":"expiration-options"},{"level":3,"title":"Filter Options","id":"filter-options"},{"level":3,"title":"Additional Options","id":"additional-options"},{"level":3,"title":"Limits","id":"limits"},{"level":2,"title":"Common Use Cases","id":"common-use-cases"},{"level":3,"title":"Rotate Log Files","id":"rotate-log-files"},{"level":3,"title":"Clean Up Temporary Files","id":"clean-up-temporary-files"},{"level":3,"title":"Offsite Backup Retention","id":"offsite-backup-retention"},{"level":3,"title":"Abort Stale Multipart Uploads","id":"abort-stale-multipart-uploads"},{"level":3,"title":"Multiple Rules on One Bucket","id":"multiple-rules-on-one-bucket"},{"level":2,"title":"Important Notes","id":"important-notes"},{"level":2,"title":"Troubleshooting","id":"troubleshooting"},{"level":3,"title":"Rules Not Taking Effect","id":"rules-not-taking-effect"},{"level":3,"title":"Objects Not Being Deleted","id":"objects-not-being-deleted"},{"level":3,"title":"Want to Temporarily Stop a Rule?","id":"want-to-temporarily-stop-a-rule"},{"level":2,"title":"Next Steps","id":"next-steps"}],"format":"markdown","word_count":1193,"content":"# Lifecycle Rules Guide\n\nAutomatically expire and delete objects based on age or prefix to manage storage costs and enforce data retention policies.\n\n## Overview\n\nLifecycle rules run automatically in the background and delete objects after a specified number of days. This is useful for cleaning up temporary files, rotating backups, meeting compliance requirements, or keeping storage costs under control.\n\n### How It Works\n\n1. You define one or more rules, each with a unique ID\n2. Each rule specifies which objects to target (by prefix) and when to expire them (by age in days)\n3. The storage system evaluates rules periodically and deletes matching objects automatically\n4. Deleted objects cannot be recovered unless versioning is enabled\n\n## Configuring Lifecycle Rules via Dashboard\n\n1. Navigate to **Object Storage** in the sidebar\n2. Click on your bucket to open the detail page\n3. Scroll to the **Lifecycle Rules** panel\n4. Click **Create Lifecycle Rule**\n5. Configure your rule:\n   - **Rule ID**: A unique name to identify this rule (e.g., `delete-old-logs`)\n   - **Expiration (days)**: Number of days after object creation before deletion (1-36,500)\n   - **Object Prefix** (optional): Only target objects whose key starts with this prefix (e.g., `logs/` or `temp/`). Leave empty to apply to all objects\n   - **Enable this rule**: Check to activate the rule immediately\n6. Click **+ Add Lifecycle Rule** to add additional rules\n7. Click **Save Rules**\n\nThe rules are applied asynchronously. It may take a few moments for the changes to take effect.\n\n## Configuring via API\n\n### Create or Update Lifecycle Rules\n\n```bash\ncurl -X PUT https://danubedata.ro/api/v1/storage/buckets/{bucket_id} \\\n  -H \"Authorization: Bearer YOUR_API_TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"lifecycle_rules\": [\n      {\n        \"ID\": \"delete-old-logs\",\n        \"Status\": \"Enabled\",\n        \"Filter\": {\n          \"Prefix\": \"logs/\"\n        },\n        \"Expiration\": {\n          \"Days\": 30\n        }\n      }\n    ]\n  }'\n```\n\n### Remove All Lifecycle Rules\n\n```bash\ncurl -X PUT https://danubedata.ro/api/v1/storage/buckets/{bucket_id} \\\n  -H \"Authorization: Bearer YOUR_API_TOKEN\" \\\n  -H \"Content-Type: application/json\" \\\n  -d '{\n    \"lifecycle_rules\": []\n  }'\n```\n\n## Configuring via AWS CLI\n\nSince DanubeData Object Storage is fully S3-compatible, you can use the AWS CLI to manage lifecycle rules directly.\n\n### Set Lifecycle Rules\n\nCreate a lifecycle configuration file `lifecycle.json`:\n\n```json\n{\n  \"Rules\": [\n    {\n      \"ID\": \"delete-old-logs\",\n      \"Status\": \"Enabled\",\n      \"Filter\": {\n        \"Prefix\": \"logs/\"\n      },\n      \"Expiration\": {\n        \"Days\": 30\n      }\n    },\n    {\n      \"ID\": \"cleanup-temp-files\",\n      \"Status\": \"Enabled\",\n      \"Filter\": {\n        \"Prefix\": \"tmp/\"\n      },\n      \"Expiration\": {\n        \"Days\": 7\n      }\n    }\n  ]\n}\n```\n\nApply the configuration:\n\n```bash\naws --endpoint-url https://s3.danubedata.ro s3api put-bucket-lifecycle-configuration \\\n  --bucket my-bucket \\\n  --lifecycle-configuration file://lifecycle.json\n```\n\n### View Current Rules\n\n```bash\naws --endpoint-url https://s3.danubedata.ro s3api get-bucket-lifecycle-configuration \\\n  --bucket my-bucket\n```\n\n### Remove All Rules\n\n```bash\naws --endpoint-url https://s3.danubedata.ro s3api delete-bucket-lifecycle \\\n  --bucket my-bucket\n```\n\n## Configuring via S3 SDKs\n\n### Python (boto3)\n\n```python\nimport boto3\n\ns3 = boto3.client(\n    's3',\n    endpoint_url='https://s3.danubedata.ro',\n    aws_access_key_id='YOUR_ACCESS_KEY',\n    aws_secret_access_key='YOUR_SECRET_KEY'\n)\n\n# Set lifecycle rules\ns3.put_bucket_lifecycle_configuration(\n    Bucket='my-bucket',\n    LifecycleConfiguration={\n        'Rules': [\n            {\n                'ID': 'delete-old-backups',\n                'Status': 'Enabled',\n                'Filter': {'Prefix': 'backups/'},\n                'Expiration': {'Days': 90},\n            },\n            {\n                'ID': 'cleanup-incomplete-uploads',\n                'Status': 'Enabled',\n                'Filter': {'Prefix': ''},\n                'AbortIncompleteMultipartUpload': {\n                    'DaysAfterInitiation': 7\n                },\n            },\n        ]\n    }\n)\n\n# View current rules\nresponse = s3.get_bucket_lifecycle_configuration(Bucket='my-bucket')\nfor rule in response['Rules']:\n    print(f\"{rule['ID']}: prefix={rule.get('Filter', {}).get('Prefix', '*')}, \"\n          f\"expires={rule.get('Expiration', {}).get('Days', 'N/A')} days, \"\n          f\"status={rule['Status']}\")\n```\n\n### Node.js (AWS SDK v3)\n\n```javascript\nimport {\n  S3Client,\n  PutBucketLifecycleConfigurationCommand,\n  GetBucketLifecycleConfigurationCommand,\n} from '@aws-sdk/client-s3';\n\nconst s3 = new S3Client({\n  endpoint: 'https://s3.danubedata.ro',\n  region: 'fsn1',\n  credentials: {\n    accessKeyId: 'YOUR_ACCESS_KEY',\n    secretAccessKey: 'YOUR_SECRET_KEY',\n  },\n  forcePathStyle: true,\n});\n\n// Set lifecycle rules\nawait s3.send(new PutBucketLifecycleConfigurationCommand({\n  Bucket: 'my-bucket',\n  LifecycleConfiguration: {\n    Rules: [\n      {\n        ID: 'delete-old-logs',\n        Status: 'Enabled',\n        Filter: { Prefix: 'logs/' },\n        Expiration: { Days: 30 },\n      },\n    ],\n  },\n}));\n\n// View current rules\nconst response = await s3.send(\n  new GetBucketLifecycleConfigurationCommand({ Bucket: 'my-bucket' })\n);\nconsole.log(response.Rules);\n```\n\n### PHP (Laravel)\n\n```php\nuse Aws\\S3\\S3Client;\n\n$s3 = new S3Client([\n    'endpoint' => 'https://s3.danubedata.ro',\n    'region' => 'fsn1',\n    'version' => 'latest',\n    'use_path_style_endpoint' => true,\n    'credentials' => [\n        'key' => 'YOUR_ACCESS_KEY',\n        'secret' => 'YOUR_SECRET_KEY',\n    ],\n]);\n\n// Set lifecycle rules\n$s3->putBucketLifecycleConfiguration([\n    'Bucket' => 'my-bucket',\n    'LifecycleConfiguration' => [\n        'Rules' => [\n            [\n                'ID' => 'delete-old-logs',\n                'Status' => 'Enabled',\n                'Filter' => ['Prefix' => 'logs/'],\n                'Expiration' => ['Days' => 30],\n            ],\n        ],\n    ],\n]);\n```\n\n## Rule Configuration Reference\n\n### Required Fields\n\n| Field | Type | Description |\n|-------|------|-------------|\n| **ID** | String (max 255) | Unique identifier for the rule |\n| **Status** | `Enabled` or `Disabled` | Whether the rule is active |\n\n### Expiration Options\n\n| Field | Type | Description |\n|-------|------|-------------|\n| **Expiration.Days** | Integer (1-36,500) | Delete objects this many days after creation |\n| **Expiration.Date** | ISO 8601 date | Delete objects after this specific date |\n\n### Filter Options\n\n| Field | Type | Description |\n|-------|------|-------------|\n| **Filter.Prefix** | String (max 1,024) | Only apply to objects whose key starts with this prefix. Empty string or omitted = all objects |\n\n### Additional Options\n\n| Field | Type | Description |\n|-------|------|-------------|\n| **NoncurrentVersionExpiration.NoncurrentDays** | Integer (1-36,500) | Delete noncurrent versions after this many days (requires versioning) |\n| **AbortIncompleteMultipartUpload.DaysAfterInitiation** | Integer (1-36,500) | Abort incomplete multipart uploads after this many days |\n\n### Limits\n\n- Maximum **100** lifecycle rules per bucket\n- Each rule ID must be unique within the bucket\n\n## Common Use Cases\n\n### Rotate Log Files\n\nDelete application logs older than 30 days:\n\n```json\n{\n  \"ID\": \"rotate-logs\",\n  \"Status\": \"Enabled\",\n  \"Filter\": {\"Prefix\": \"logs/\"},\n  \"Expiration\": {\"Days\": 30}\n}\n```\n\n### Clean Up Temporary Files\n\nRemove temp files after 24 hours:\n\n```json\n{\n  \"ID\": \"cleanup-temp\",\n  \"Status\": \"Enabled\",\n  \"Filter\": {\"Prefix\": \"tmp/\"},\n  \"Expiration\": {\"Days\": 1}\n}\n```\n\n### Offsite Backup Retention\n\nKeep backup snapshots for 90 days:\n\n```json\n{\n  \"ID\": \"backup-retention\",\n  \"Status\": \"Enabled\",\n  \"Filter\": {\"Prefix\": \"backups/\"},\n  \"Expiration\": {\"Days\": 90}\n}\n```\n\n### Abort Stale Multipart Uploads\n\nClean up incomplete uploads that were never finished:\n\n```json\n{\n  \"ID\": \"abort-incomplete-uploads\",\n  \"Status\": \"Enabled\",\n  \"Filter\": {\"Prefix\": \"\"},\n  \"AbortIncompleteMultipartUpload\": {\"DaysAfterInitiation\": 7}\n}\n```\n\n### Multiple Rules on One Bucket\n\nYou can combine multiple rules targeting different prefixes:\n\n```json\n[\n  {\n    \"ID\": \"short-lived-cache\",\n    \"Status\": \"Enabled\",\n    \"Filter\": {\"Prefix\": \"cache/\"},\n    \"Expiration\": {\"Days\": 7}\n  },\n  {\n    \"ID\": \"medium-lived-logs\",\n    \"Status\": \"Enabled\",\n    \"Filter\": {\"Prefix\": \"logs/\"},\n    \"Expiration\": {\"Days\": 30}\n  },\n  {\n    \"ID\": \"long-lived-reports\",\n    \"Status\": \"Enabled\",\n    \"Filter\": {\"Prefix\": \"reports/\"},\n    \"Expiration\": {\"Days\": 365}\n  }\n]\n```\n\n## Important Notes\n\n- **Deletion is permanent**: Once an object expires, it is deleted and cannot be recovered unless versioning is enabled on the bucket.\n- **Evaluation delay**: Rules are evaluated periodically, not at the exact moment an object reaches its expiration age. Objects may persist for a short time after their expiration date.\n- **Prefix matching**: Prefixes match from the start of the object key. A prefix of `logs/` matches `logs/app.log` and `logs/2024/error.log`, but not `old-logs/app.log`.\n- **Empty prefix**: Omitting the prefix or setting it to an empty string applies the rule to all objects in the bucket.\n- **Versioned buckets**: Use `NoncurrentVersionExpiration` to clean up old object versions. The `Expiration.Days` rule only affects the current version.\n\n## Troubleshooting\n\n### Rules Not Taking Effect\n\n- Verify the rule status is **Enabled**, not Disabled\n- Check the object prefix matches your objects (prefixes are case-sensitive)\n- Allow time for the rules to be evaluated; expiration is not instantaneous\n\n### Objects Not Being Deleted\n\n- The object may not have reached the expiration age yet. Expiration is based on the object's creation date, not its last modified date.\n- Ensure the prefix matches correctly. For example, a prefix of `logs` (without trailing slash) also matches `logs-archive/file.txt`.\n\n### Want to Temporarily Stop a Rule?\n\nSet the rule's status to **Disabled** instead of deleting it. You can re-enable it later without reconfiguring.\n\n## Next Steps\n\n- [Object Storage Product Overview](https://docs.danubedata.ro/object-storage) - Full feature documentation\n- [Object Storage Quick Start](https://docs.danubedata.ro/object-storage-quickstart) - Get started guide\n- [Object Storage Security](https://docs.danubedata.ro/object-storage-security) - Access control and encryption\n\n---\n\n**Questions?** Contact support at support@danubedata.ro\n","prev":null,"next":null,"index_url":"https://docs.danubedata.ro/index.json"}