minio/minio
Versioning and Object Lock
How MinIO tracks multiple versions of an object and enforces immutability rules on top of them.
Versioning
When versioning is enabled on a bucket, every PUT (including DELETE markers) becomes a new version of the object. The mechanics:
- Bucket-level config:
internal/bucket/versioning/parses the XML; bucket metadata stores the resulting state (Enabled,Suspended). - On-disk:
xl.meta(defined incmd/xl-storage-format-v2.go) carries the full list of versions, including non-current and "free" versions. - Listing:
ListObjectVersionsincmd/bucket-listobjects-handlers.gowalks thexl.metatree via the metacache. - Garbage collection: lifecycle rules can expire non-current versions; reclaimable "free versions" are removed by the scanner.
Excluded prefixes
internal/bucket/versioning/ supports an excludedPrefixes list — paths that bypass versioning (used by Veeam-style workloads where a sub-prefix should remain unversioned even on a versioned bucket).
Delete markers
A DELETE on a versioned object writes a "delete marker" — a zero-byte version that suppresses the object on subsequent GETs unless the request asks for an explicit version. Delete markers replicate to peer sites under the standard replication rules; see Bucket replication flow.
Object Lock
Object Lock layers retention and legal-hold semantics on top of versioning. The model lives in internal/bucket/object/lock/.
| Concept | What it does |
|---|---|
| Retention mode | GOVERNANCE (privileged user can override) or COMPLIANCE (no one can override). |
| Retain Until | Per-version timestamp; the version cannot be deleted before then. |
| Legal hold | Independent flag that blocks deletion regardless of retention. |
| Default lock | A bucket-wide default applied at PUT time. |
The runtime checks happen in:
cmd/bucket-object-lock.go— apply retention defaults on PUT.cmd/object-handlers.go— enforce on DELETE / DeleteObjects.cmd/admin-bucket-handlers.go— admin-side validation for site replication.
Compliance vs. governance
GOVERNANCEallows users with the right permission (BypassGovernanceRetention) to delete a still-locked version. Useful in dev/test.COMPLIANCEis absolute; only the system itself can delete a version after the retention expires.
How they interact
graph TD
PUT[PutObject] --> VER{versioning?}
VER -- yes --> XLM[Append new version to xl.meta]
VER -- no --> XLM2[Replace single version]
XLM --> LOCK{Object Lock default?}
LOCK -- yes --> RET[Apply retention + legal-hold]
LOCK -- no --> END[done]
DEL[DeleteObject] --> CHECK{Locked + not expired?}
CHECK -- yes --> ERR[AccessDenied]
CHECK -- no --> MARK[Write delete marker / free version]Replication and locks
- Site replication carries the bucket's versioning state and Object Lock config (
cmd/site-replication.go). - Bucket replication preserves retention metadata when replicating versions.
- Object Lock cannot be disabled on a bucket once enabled.
Storage interactions
cmd/xl-storage-free-version.go covers the post-deletion housekeeping: a deleted version is converted to a free version that the scanner can reclaim once retention expires and no replication target needs it anymore.
Test entry points
make test-versioning(docs/bucket/versioning/versioning-tests.sh).make test-iamexercises retention/legal-hold permissions via STS.
Where to start reading
internal/bucket/versioning/versioning.gointernal/bucket/object/lock/lock.gocmd/xl-storage-format-v2.gocmd/bucket-object-lock.gocmd/object-handlers.go(search forVersioningandObjectLock)
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.