Object Storage: Reason About Identity, Integrity, and Lifecycle
Reason about object storage through buckets and keys, immutable naming, direct uploads, multipart integrity, strong consistency, versioning, lifecycle policies, metadata ownership, and cross-system failure boundaries.
Personal learning atlas by Tran Trong Thuc · About this Atlas · Atlas last updated Sep 10, 2026
Object Storage: Reason About Identity, Integrity, and Lifecycle
TL;DR
Object storage is built around a simple abstraction:
bucket + object key -> bytes + metadataThat simplicity is powerful, but production systems still need explicit contracts for identity, authorization, upload completion, integrity, lifecycle, and metadata ownership.
A useful mental model is:
The object store can durably hold bytes while your application is still wrong about whether those bytes are complete, owned by the right tenant, safe to expose, or ready for processing.
1. Object storage is not a filesystem with a bigger disk
Object storage organizes data as independent objects. Each object has an identifier, bytes, and metadata. APIs typically expose operations such as put, get, head, list, copy, and delete.
This differs from a POSIX-style filesystem where applications manipulate directories, file descriptors, offsets, permissions, and mutable byte ranges.
A practical distinction:
filesystem
directory hierarchy
path lookup
mutable files / byte ranges
local or mounted filesystem semantics
object storage
bucket namespace
object key lookup
whole-object API semantics
metadata + policy around each object
service boundary reached over an APIDo not design against object storage by assuming filesystem behavior that the object API never promised.
2. Bucket and object key form the storage identity
A key such as:
tenants/t42/invoices/2026/09/inv_81a7.pdflooks hierarchical, but the slash-separated pieces are still characters in one key. Prefixes are useful conventions, not independent directories with filesystem semantics.
Useful key design questions:
- Does the key expose private information that should not appear in logs or URLs?
- Is the key stable if a user renames a file?
- Can two concurrent uploads accidentally choose the same key?
- Does the key encode tenant ownership clearly enough for policy and operations?
- Can lifecycle or inventory jobs select the intended object family by prefix or tags?
3. Prefer immutable storage identity over mutable human names
Human-facing filenames are poor primary identifiers.
Consider:
uploads/report.pdfTwo users, retries, or concurrent replacements can collide on the same key. If the application overwrites the key in place, caches, asynchronous processors, and audit trails can disagree about which bytes “report.pdf” meant at a particular time.
A safer design is:
object key: tenants/t42/uploads/01J.../original.pdf
logical name: report.pdfThe database stores the logical filename and points to an immutable storage key.
This separates business identity from storage identity. A rename can change metadata without moving bytes, while replacement can create a new object identity rather than silently mutating an old one.
4. Object storage should not automatically become your application source of truth
For many systems, the object store is authoritative for the bytes but the application database is authoritative for business metadata.
Example:
object store owns:
bytes
storage-level checksum
object version / storage metadata
application database owns:
tenant_id
logical filename
media type accepted by the product
processing state
visibility / authorization state
upload ownership
retention policy chosen by the businessThat distinction makes reconciliation possible.
If an object exists but no database row references it, it may be an orphan. If a row claims ready but the object is missing, the application metadata is inconsistent. Those are different failures and need different repair paths.
5. Modern S3 consistency is stronger than old folklore
Amazon S3 provides strong read-after-write consistency for object PUT and DELETE operations, including overwrites, and for subsequent GET and LIST requests after a successful write response.
Updates to a single key are atomic: concurrent readers observe the old object or the new object, not a partially mixed object.
Therefore, do not explain a missing S3 object after a successful PUT by repeating the old “S3 is eventually consistent” rule.
But strong object-store consistency does not make your multi-system workflow atomic.
This can still fail:
1. PostgreSQL row -> status = ready
2. upload to S3 -> network error before completion
3. worker reads row
4. worker cannot retrieve complete objectThe problem is cross-system coordination, not S3 read-after-write consistency.
6. Direct upload removes your application server from the byte path
Large uploads do not always need to flow through an application server.
A common pattern is:
Benefits include reducing application-server bandwidth and avoiding proxying very large bodies through workers that exist mainly for business logic.
The important word is scoped. A direct-upload credential or presigned URL is a capability. Its key, operation, expiration, content expectations, and tenant association should be deliberately constrained.
7. A presigned URL is delegated authority, not proof of business ownership
Do not accept this sequence:
client supplies arbitrary bucket/key
server signs itPrefer:
server verifies tenant + intent
server allocates key under owned namespace
server records pending upload
server signs only the required operationThe object key should be derived from trusted application state, not blindly accepted from the client.
8. Same-key upload can be an overwrite
In S3, uploading to an existing key replaces the current object when versioning does not provide a new visible identity to the application.
That matters for retries and presigned uploads. A URL that remains valid may be usable more than once before expiry, and the same key can be overwritten.
If “create exactly one immutable asset” is the business intent, use a unique allocated key and, when supported by the workflow, conditional write semantics that reject an existing key instead of relying on “we probably only upload once.”
Immutability makes retries, CDN behavior, background processing, and auditing easier to reason about.
9. Multipart upload is a construction protocol, not a partially visible object
Large objects can be uploaded as independent parts.
Multipart upload separates the workflow into:
create multipart upload
-> upload part 1
-> upload part 2
-> ...
-> complete multipart upload
-> final object existsParts can be retried independently, which is valuable for large transfers or unreliable networks.
But the application should distinguish:
parts uploaded != object finalizedDo not mark business metadata ready just because every client-side part request returned success. The completion operation is the boundary that asks the object store to assemble the final object.
Incomplete multipart uploads also need cleanup. A lifecycle policy can abort abandoned multipart uploads so failed clients do not leave indefinite storage residue.
10. Integrity needs a checksum contract
For direct or multipart uploads, decide:
- Which checksum algorithm is accepted?
- Who calculates it: client, trusted backend, object store, or more than one participant?
- Is the checksum stored in application metadata for later reconciliation?
- Does the processing pipeline verify the expected checksum before expensive work?
This becomes especially useful when objects cross systems, Regions, or long-lived archives.
11. Do not assume ETag means MD5
An S3 ETag is useful object metadata, but it is not a universal content-MD5 contract.
For example, multipart-uploaded objects do not use a plain MD5 digest of the complete object as their ETag. Some encryption paths also produce ETags that are not an MD5 digest of object data.
Therefore this is unsafe as a universal integrity rule:
if local_md5 == ETag:
upload is validUse the object's explicit checksum facilities when your application needs a checksum guarantee.
12. Versioning changes overwrite and delete semantics
S3 Versioning allows multiple versions of the same object key to coexist with distinct version IDs.
With versioning enabled:
PUT same key -> new version
previous version -> remains noncurrent
DELETE without version ID -> normally creates a delete markerThis can make accidental overwrite or deletion recoverable, but it also means storage lifecycle and deletion logic must account for noncurrent versions.
Versioning is not a substitute for application history. Your product may still need to record which object version was attached to which invoice, user submission, model artifact, or audit event.
If exact replay matters, persist the storage version identifier with the business record instead of only storing a mutable key.
13. Lifecycle policy is part of storage design
Object storage is attractive partly because data can outlive the process that created it. Without lifecycle ownership, that strength becomes unbounded cost and forgotten data.
A lifecycle rule can express policies such as:
new object
-> frequent-access storage class
-> transition after N days
-> archive after M days
-> expire when retention allowsLifecycle decisions should come from business data classes, not one global “move everything to archive after 30 days” rule.
Consider separately:
- active product assets;
- reconstructable derived artifacts;
- customer exports;
- compliance records;
- failed/incomplete uploads;
- noncurrent versions;
- temporary processing outputs.
The cost model is not only storage price per GB. Retrieval latency, retrieval charges, minimum storage duration, requests, replication, and operational recovery expectations can matter too.
14. Deletion is a workflow, not just one DELETE request
A business “delete file” operation may need to coordinate:
authorization
-> hide from product reads
-> delete or tombstone application metadata
-> delete current object / version
-> delete derivatives / thumbnails
-> purge caches if required
-> retain audit evidence
-> honor legal or retention constraintsWith versioning or Object Lock, “deleted from normal reads” may not mean “all bytes permanently erased.”
Your API should distinguish product visibility, recoverability, retention, and permanent deletion rather than collapsing them into one vague deleted = true flag.
15. Object Lock and retention solve a different problem from backup
S3 Object Lock can protect object versions with write-once-read-many retention semantics. It requires versioning and can prevent protected versions from being overwritten or permanently deleted during the retention window.
That is useful for compliance or tamper-resistance requirements, but it is not the same thing as a complete backup strategy.
A backup design still asks:
- Can we recover after a bad application migration?
- Is the recovery copy isolated enough from the same credentials and automation?
- Can we restore metadata and object references together?
- Have we tested restore time and restore correctness?
Retention, replication, versioning, and backup address overlapping but different failure modes.
16. Metadata is usually small enough to keep transactional
Do not put every business attribute into opaque object metadata simply because the object store supports metadata fields.
Transactional databases are usually better at relationships, constraints, state transitions, search predicates, and multi-row invariants.
A common split is:
PostgreSQL row
id
tenant_id
object_key
object_version
checksum
logical_name
declared_media_type
verified_media_type
size_bytes
status
created_at
Object store
immutable bytes
storage metadataThis keeps authoritative workflow state queryable and lets object storage specialize in durable byte storage.
17. Content type and filename are untrusted input
A client-provided filename or Content-Type header is not proof that the uploaded bytes are safe or actually match the declaration.
For user uploads, production systems commonly separate:
upload accepted
-> object quarantined / not public
-> inspect size and magic bytes / media format
-> malware or policy scanning when required
-> generate safe derivatives
-> mark ready for intended useDo not publish an upload merely because the object store accepted it.
The exact security pipeline depends on the product, but the storage lesson is durable: storage acceptance is not application validation.
18. Background processing needs immutable input identity
Object storage pairs naturally with asynchronous processing:
upload completed
-> enqueue object_id + immutable key/version
-> worker downloads exact input
-> process
-> write derivative under new immutable key
-> transactionally update metadataAvoid queue messages that say only:
process latest file at uploads/user-7/avatar.jpgIf the key is overwritten before the worker runs, the worker may process different bytes from the event that triggered it.
Prefer an immutable key or explicit object version so the job refers to one stable input.
19. Cross-system workflows need reconciliation
Your database and object store do not share one ordinary ACID transaction.
That creates states such as:
object exists, DB row missing
DB row exists, object missing
DB says pending, object completed
DB says ready, checksum mismatch
object deleted, derivative still existsDesign a reconciliation job that can classify and repair or quarantine these states.
A durable workflow often uses state transitions:
State machines make partial failure visible instead of pretending a distributed workflow is atomic.
20. Production scenario: database says ready before upload is truly finalized
A media API creates row asset_42 and returns a presigned multipart-upload workflow. The client uploads all parts. Before CompleteMultipartUpload and checksum verification finish, the client calls POST /assets/asset_42/publish.
The API trusts the client's claim and marks the row ready. A background transcoder reads the row immediately. Meanwhile a retry reuses the same human-derived key users/u9/video.mp4, overwriting what another workflow expects.
Impact: workers intermittently see a missing or unexpected object; users can receive the wrong bytes under a stable URL; abandoned multipart parts accumulate; support sees database records that say ready even though storage state never reached the intended final object.
Root cause: the system confused client-side upload progress with object-store completion, used a mutable shared key as identity, and had no checksum-backed finalize transition between storage state and business state.
Correct pattern: allocate a unique immutable key before signing, keep the database row pending, upload directly with a tightly scoped capability, complete multipart upload, verify the finalized object and expected checksum/size, then transition metadata to ready. Queue workers by immutable object identity, clean abandoned multipart uploads with lifecycle rules, and reconcile orphan/missing states explicitly.
Self-check: does strong S3 consistency remove the need for an upload state machine?
Suppose S3 strongly exposes a successful completed PUT to subsequent reads. Can the application safely replace its pending -> ready state machine with “if the key exists, the upload is ready”?
Show the reasoning
No.
Strong read-after-write consistency answers a storage visibility question: after a successful write, what do later object-store reads observe?
Your application still has separate questions:
- Was this key allocated to the authenticated tenant?
- Did multipart completion finish?
- Does the final size/checksum match the expected upload?
- Did content validation or security scanning pass?
- Did the database record the exact object identity/version?
- Is the object approved for public or downstream processing?
Those facts span application policy and multiple systems. A state machine is how the application represents those facts and partial failures explicitly.
Production checklist
- Identity: allocate immutable object IDs/keys instead of using human filenames as storage identity.
- Namespace: make tenant or ownership boundaries explicit without leaking unnecessary private data in keys.
- Source of truth: state which system owns bytes and which owns business metadata/workflow state.
- Consistency: do not rely on obsolete eventual-consistency assumptions for modern S3
PUT/DELETE/GET/LISTbehavior. - Authorization: scope presigned capabilities to the intended bucket, key, operation, and lifetime.
- Finalize: separate upload progress from completed object state.
- Multipart cleanup: abort abandoned multipart uploads through lifecycle policy or explicit cleanup.
- Integrity: verify checksum/size when correctness depends on exact bytes.
- ETag: do not universally treat ETag as content MD5.
- Validation: treat filename, declared media type, and uploaded bytes as untrusted until product checks pass.
- Versioning: decide whether overwrite/delete recovery needs object versioning and persist version IDs when exact replay matters.
- Lifecycle: classify active, temporary, archive, failed-upload, and noncurrent-version retention separately.
- Deletion: distinguish product hiding, recoverability, retention, and permanent deletion.
- Workers: send immutable key/version identity to asynchronous processors.
- Reconciliation: detect orphan objects, missing objects, stale metadata, and failed derivatives.
- Observability: measure upload failures, finalize latency, multipart abandonment, checksum failures, storage growth, lifecycle transitions, and processing lag.
Agent rule
When proposing object storage, do not stop at “put files in S3.” Specify object identity, who owns business metadata, how upload authority is delegated, what proves completion and integrity, whether keys are mutable, how asynchronous workers identify exact bytes, what versioning/lifecycle/deletion mean, and how database/object-store divergence is reconciled.
Sources
- Amazon S3 User Guide — What is Amazon S3? / data consistency model
- Amazon S3 User Guide — Naming Amazon S3 objects
- Amazon S3 User Guide — Presigned URLs
- Amazon S3 User Guide — Multipart upload overview
- Amazon S3 User Guide — Checking object integrity
- Amazon S3 API — Object / ETag semantics
- Amazon S3 User Guide — How S3 Versioning works
- Amazon S3 User Guide — Managing object lifecycle
- Amazon S3 User Guide — Object Lock
This lesson is classified as evolving with a 180-day review target because provider APIs, checksum support, storage classes, security defaults, and lifecycle features evolve while the core object-identity and cross-system workflow model remains durable.
Search Indexes: Reason About Analysis, Relevance, and FreshnessNew
Reason about search indexes through inverted indexes, analyzers, text and keyword mappings, relevance scoring, near-real-time visibility, derived documents, reindexing, and operational freshness.
Coupling & Cohesion: Keep Change LocalNew
Operate on software boundaries by measuring change propagation, increasing cohesion, reducing unnecessary coupling, clarifying ownership, tightening interfaces, breaking cycles, and testing contracts.