The object storage model: buckets, keys, metadata, versioning
coreintermediateObject storage holds data as whole, immutable objects — not files in a directory tree and not rows in a table. A bucket is a flat namespace; every object inside it is addressed by a key, a string that is the object's entire identity (there are no real subdirectories, only keys that share a prefix). Each object carries metadata alongside its bytes — content type, custom headers, timestamps. Versioning, once turned on for a bucket, keeps every past copy of an object instead of overwriting it on write or delete. Lifecycle rules then automate what happens to those objects and versions over time: moving them to cheaper storage tiers or expiring them, based on age or prefix, with no application code involved.
Think of it as
Think of a bucket as a warehouse that only stores sealed, labeled boxes — never loose paper you can edit in place. The key is the barcode stuck on the box: read it and you get the box, but there is no shelf structure the warehouse actually enforces, just barcodes that happen to share a prefix like "invoices/2026/". The metadata is the shipping label on the outside of the box (what's inside, when it arrived) — readable without opening the box. Versioning is the warehouse keeping every previous box that ever had that barcode instead of throwing the old one out when a new one arrives. Lifecycle rules are a standing instruction taped to the warehouse wall — "move anything untouched for 90 days to the cheap back room; shred anything untouched for a year" — that the warehouse staff carries out on a schedule, with nobody having to ask them each time.
What we're doing: See what a DELETE actually does once versioning is enabled, and how a lifecycle rule cleans up what it leaves behind.
- 5
- The DELETE does not remove v1 or v2 — it adds a new "delete marker" version that becomes current, which is why GET now reports not-found even though data still exists in the bucket.
- 9
- Both prior versions are still stored and still billed until something explicitly removes them — versioning trades "delete is reversible" for "delete alone does not reduce storage cost."
- 12
- A lifecycle rule targeting noncurrent versions is what actually reclaims that storage automatically, on a schedule, with no application code involved.
Why this works: Versioning and lifecycle rules are usually adopted together for exactly this reason — versioning alone protects against accidental overwrite/delete but silently grows storage cost forever unless a lifecycle rule is paired with it to expire old versions.
Enabling versioning without a matching lifecycle rule
Wrong
Better
What you see: Storage cost for a bucket climbs steadily even though the number of "current" objects looks stable — because every overwrite and delete is silently retained as a noncurrent version with no expiration.
Why: Versioning has no built-in cleanup — it is a pure "keep everything" mechanism until a lifecycle rule (or manual deletion) removes noncurrent versions, so the two are almost always configured as a pair, not versioning alone.
- Client → Bucket: PUT inv-4471.pdf (creates v1 (current))
- Client → Bucket: PUT inv-4471.pdf (creates v2 (current), v1 kept)
- Client → Bucket: DELETE inv-4471.pdf (adds a delete marker (current) — v1, v2 still stored and billed)
The four core concepts of the object storage model
Remember: Bucket = flat container, key = full object identity (no real folders, only shared prefixes), metadata = data about the object stored alongside it. Versioning keeps every version; DELETE adds a marker rather than erasing data. Lifecycle rules are what actually reclaim storage from old versions — configure them together, not versioning alone.
See also: multipart upload and signed urls · object storage vs application servers

