The problem
Bucket versioning protects against accidental overwrite and deletion, but old generations remain billable until lifecycle rules explicitly delete them. In rewrite-heavy buckets, archived generations can become the majority of stored bytes even when the live object set looks healthy.
Why it happens
- Versioning is enabled for recovery, but archived-generation cleanup is never added to the bucket lifecycle rules.
- Teams see a lifecycle policy in place and assume older generations are covered even when the rules only manage live objects.
- Rewrite-heavy logs, exports, and mutable artifact buckets generate stale generations faster than owners review storage behavior.
What this means for cost
Estimated monthly
$75 to $1,600/mo
Estimated annual
$900 to $19,200/yr
This waste pattern often shows up as $75 to $1,600/mo in recurring monthly cost, or roughly $900 to $19,200/yr if it sits untouched for a year.
How to detect GCS versioning without noncurrent cleanup
The strongest signal is a bucket with versioning enabled and no lifecycle rule that actually ages out older generations. A generic lifecycle rule can still leave this detector firing when it never limits older versions.
Check whether the bucket has versioning enabled and whether lifecycle rules would actually clean up older object generations:
gcloud storage buckets describe gs://my-bucket --format=json
In the bucket description, confirm both:
versioning.enabledistrue- Lifecycle rules either bound retention with
ageor explicitly target archived or noncurrent versions, such asisLive=false,numNewerVersions,daysSinceNoncurrentTime, ornoncurrentTimeBefore
If versioning is enabled but lifecycle only deletes live objects, inspect storage growth over time. Buckets with repeated rewrites, logs, or mutable artifact names are strong candidates.
How this detector confirms GCS versioning cleanup gaps
Cloud Waste Hunter does not treat generic lifecycle presence as enough. The detector only suppresses a finding when it sees a Delete rule that appears to meaningfully limit older version retention. That keeps the page aligned to the implementation boundary: versioning plus missing effective cleanup for versioned buildup.
How to fix GCS versioning without noncurrent cleanup
Define a lifecycle rule that limits how long older generations remain in the bucket.
resource "google_storage_bucket" "versioned" {
name = "my-versioned-bucket"
location = "US"
versioning {
enabled = true
}
lifecycle_rule {
condition {
age = 60
with_state = "ARCHIVED"
num_newer_versions = 5
}
action {
type = "Delete"
}
}
}
If recovery requirements differ across data types, split the data into purpose-specific buckets before applying cleanup.
Caveats and overlap boundaries
This detector is narrower than a generic “bucket has no lifecycle policy” check. A bucket can have lifecycle rules and still be flagged here if those rules never clean up archived generations created by versioning. Conversely, a bucket with an age-based or explicit noncurrent-version delete rule is treated as aligned even if the retention window is conservative.
If the real issue is a bucket with no lifecycle policy at all, that is the broader lifecycle-governance problem and the adjacent gcp-gcs-bucket-missing-lifecycle detector may also fire. This page is specifically about versioning-related storage sprawl.
How Cloud Waste Hunter helps
Cloud Waste Hunter is being built to identify versioned buckets missing effective cleanup controls and point teams toward safer lifecycle policies without assuming generic lifecycle presence is enough. For the broader storage review, continue into the GCP Storage Cost Optimization guide.
FAQ
Can I keep versioning and still control cost?
Yes. The key is to retain historical generations only as long as your recovery needs require, then let lifecycle rules clean up or transition the rest.
Does any lifecycle policy count as cleanup for this detector?
No. The detector looks for delete rules that actually limit older version buildup, including age-based retention or explicit archived-version cleanup. A lifecycle policy that only touches live objects does not suppress the finding.