s3-cleanup
Delete S3 objects older than N days from a bucket prefix. Daily summary of bytes freed. Dry-run mode for the first few runs so you can preview without accidentally nuking anything.
Use case
S3 buckets accumulate. Build artifacts, log dumps, temp files, expired exports — they sit there forever and quietly cost money. S3 Lifecycle Policies handle this in theory, but they're a pain to author for one-off cases and they apply silently with no notification. This workflow runs daily, deletes by age, and emails you a one-line summary so you know it ran and what it cleaned.
This is a YAML workflow, not a skill — pure plumbing, no AI value.
Setup
- Create an
awscredential withs3:ListBucket,s3:DeleteObject, ands3:GetObjecton the target bucket - Edit
workflow.yaml: -BUCKET— your bucket name (nos3://prefix) -PREFIX— path inside the bucket (trailing slash matters; empty string = whole bucket) -RETENTION_DAYS— anything older than this gets deleted -DRY_RUN—1for first runs (preview only), then flip to0once you trust it - Schedule daily (or weekly for low-churn buckets)
Pipeline
- cleanup —
runtimeenv(bash + AWS CLI) — lists, filters byLastModified, deletes (or previews) - notify —
message— sends the summary
Safety notes
- Always start with
DRY_RUN=1for at least one run, ideally a week. Verify the WOULD DELETE list matches your expectations - The CLI uses your credential's IAM permissions — scope the policy tight (
s3:DeleteObjectonly on the specific bucket+prefix) - If you accidentally delete the wrong objects and the bucket has versioning, recovery is
aws s3api restore-object— confirm versioning is enabled before relying on it as a safety net - This workflow does NOT delete object versions or delete markers — for full purge of a versioned bucket, you need a different cleanup pattern
Customization
- Multiple prefixes — duplicate the cleanup task per prefix
- Per-prefix retention — different
RETENTION_DAYSper task - Pattern filter — add a
--queryclause that filters on Key as well as LastModified, e.g.Contents[?LastModified<=\...` && contains(Key, '.tmp')]` - Cross-account — assume a role first via
aws sts assume-rolein the script
Source
See workflow.yaml.