Goal: stop paying for data nobody reads, without losing data somebody needs.
Lifecycle rules (set at bucket creation or after):
- Transition objects to Nearline/Coldline/Archive after N days of non-access for backups and logs.
- Delete objects after their retention need expires (build artifacts, temp exports).
- Abort incomplete multipart uploads after a few days; abandoned uploads bill as storage.
```
gcloud storage buckets update gs://[BUCKET] --lifecycle-file [RULES-JSON]
```
Versioning: enable it for buckets where overwrites must be recoverable (terraform state, configs). Know that every version bills as a full object; pair versioning with a lifecycle rule that deletes noncurrent versions after N days, or costs grow silently.
Public access prevention: enforce it on every bucket that should never be public. It makes public ACLs fail closed even if someone misconfigures IAM later.
```
gcloud storage buckets update gs://[BUCKET] --public-access-prevention
```
Traps:
- Lifecycle rules apply to current AND noncurrent versions; write rules for both or versions accumulate.
- Archive class has retrieval costs and minimum durations; transitioning tiny frequently-read objects to Archive loses money.
- Uniform bucket-level access plus public access prevention is the sane default for new buckets. Set both at creation.
Verify: after applying, check the bucket config, upload a test object, and confirm the lifecycle JSON matches intent. Revisit storage metrics monthly.