Blob storage & lifecycle
Access tiers, lifecycle policies, cost.
A storage account's blob service is the records department of an office. Hot is the tray on your desk: expensive floor space, instant reach. Cool is the filing cabinet down the hall. Cold is the basement storeroom. Archive is an off-site warehouse where keeping a box costs pennies a month, but getting it back means filing a request and waiting hours for a truck. Azure Blob Storage prices the same byte four different ways depending on which shelf it sits on. *Lifecycle management* is the clerk who walks files to cheaper shelves as they age, automatically, in the background, on Azure's schedule rather than yours.
Blob storage is Azure's *object storage*. Data lives as blobs (binary large objects, a formal way of saying "a file's worth of bytes") inside containers, which are flat, bucket-like groupings with no real folder tree underneath. You reach a blob by web address (an HTTPS URL, the same kind of link your browser uses), not by a filesystem path. Blobs come in three flavors. Block blobs hold files, backups and media, and they are the overwhelming majority of what anyone stores. Append blobs hold logs you keep adding lines to. Page blobs back virtual machine disks. Access tiers apply to block blobs only. A lifecycle policy can also point at append blobs, but only to delete them, never to move them between tiers, and the exam likes that distinction. The previous lesson covered the account shell: SKUs (stock keeping units, Azure's label for a pricing and performance option) and redundancy. This one goes inside the shell, because tiering is the largest storage cost lever an administrator actually controls.
Four price points for the same byte
Every tier trades storage cost against access cost. As the price of a gigabyte (GB) sitting still goes down, the price of reading it goes up, both per operation and per gigabyte pulled back. Hot costs the most to store and the least to read. Cool roughly halves the storage bill, charges more per read, and carries a *30-day minimum stay*: delete the blob or re-tier it sooner and you are billed for the leftover days anyway. Cold became generally available in 2023 and is a magnet for newer exam questions. It is cheaper again, with a *90-day minimum*, and it stays online, so reads still come back in milliseconds. Archive cuts the per-GB storage price by more than ten times against Hot, but it is offline. Those bytes sit on media that cannot answer a read at all until you *rehydrate* the blob back to an online tier, and its minimum stay is *180 days*.
The account carries a *default access tier* (Hot, Cool, or Cold) that lands on any blob uploaded without one. Archive can never be the default. You set it per blob, or a lifecycle policy sets it for you. Watch for the pricing inversion here. A blob you read often costs *more* in Archive than in Hot, because retrieval charges swallow the storage savings whole. Tier by an access pattern you have measured, not by instinct.
# Upload a nightly DB dump straight into Cool.# Entra ID auth (--auth-mode login) — no account keys; you need the# Storage Blob Data Contributor role on the account or container.az storage container create \--account-name stsecopslog01 --name backups --auth-mode login# { "created": true }az storage blob upload \--account-name stsecopslog01 --container-name backups \--name db-dump-2026-07-13.bak --file ./db-dump.bak \--tier Cool --auth-mode login# {# "etag": "\"0x8DDC1B2A4F3E9A0\"",# "lastModified": "2026-07-13T09:12:44+00:00"# }# Verify the tier landed. If it had come from the account default# instead, properties.blobTierInferred would be true (the portal# shows it as "Cool (inferred)").az storage blob show \--account-name stsecopslog01 --container-name backups \--name db-dump-2026-07-13.bak --auth-mode login \--query "properties.blobTier" -o tsv# Cool
Archive is cheap because it is offline
An archived blob keeps its *metadata* online. You can list it, read its properties, even delete it. The *content* is what goes dark, and it stays unreadable until you rehydrate. Rehydration copies the data off the offline media back to an online tier, and you pick one of two speeds. Standard can take *up to 15 hours*. High jumps the queue and can finish in *under one hour* for blobs below 10 GB, at a retrieval fee several times larger. You can upgrade a rehydration that is already running from Standard to High. You cannot slow one down and you cannot cancel one, and the blob keeps billing at Archive rates until the copy lands. The exam likes a second pattern too. az storage blob copy start copies an archived blob into a *new* blob on an online tier and leaves the cold original untouched. That sidesteps Archive's early-deletion fee, and it suits an archived compliance record that is not allowed to move.
# Push last year's dump to Archive (per-blob; policies do this at scale)az storage blob set-tier \--account-name stsecopslog01 --container-name backups \--name db-dump-2025-07-01.bak --tier Archive --auth-mode login# (no output — exit code 0)# Need it back for an audit? Rehydrate with High priority.az storage blob set-tier \--account-name stsecopslog01 --container-name backups \--name db-dump-2025-07-01.bak --tier Hot \--rehydrate-priority High --auth-mode login# Poll: tier stays Archive until rehydration completes.az storage blob show \--account-name stsecopslog01 --container-name backups \--name db-dump-2025-07-01.bak --auth-mode login \--query "[properties.blobTier, properties.rehydrationStatus]" -o tsv# Archive# rehydrate-pending-to-hot
Lifecycle policies: rules that pay for themselves
Re-tiering blobs one at a time stops working the moment there are a million of them. A lifecycle management policy is the standing instruction you leave with the clerk. It is a JSON (JavaScript Object Notation, a plain-text format for structured data) document attached to the storage account, holding a list of *rules*. Each rule has *filters* that decide which blobs it touches (blob type, name prefix, index tags) and *actions* keyed to age: tier to Cool, Cold or Archive, or delete. Age can be counted from the last change (daysAfterModificationGreaterThan), from creation (daysAfterCreationGreaterThan), or from the last read (daysAfterLastAccessTimeGreaterThan). That last one only behaves properly once *last-access-time tracking* is switched on for the account. It ships off, because every access-time update bills as an "other operation", capped at once per blob per day. You do not schedule the engine and you cannot poke it into running. A new or edited policy takes up to 24 hours to come into effect, and the run then grinds through the account in the background at its own pace. Budget more than a day before the first actions land.
# lifecycle.json — tier down by age, delete after a year{"rules": [{"enabled": true,"name": "age-out-db-dumps","type": "Lifecycle","definition": {"filters": {"blobTypes": ["blockBlob"],"prefixMatch": ["backups/db-dump"]},"actions": {"baseBlob": {"tierToCool": { "daysAfterModificationGreaterThan": 30 },"tierToArchive": { "daysAfterModificationGreaterThan": 90 },"delete": { "daysAfterModificationGreaterThan": 365 }}}}}]}# Attach it to the account (management plane — resource group needed)az storage account management-policy create \--account-name stsecopslog01 --resource-group rg-storage-prod \--policy @lifecycle.json# {# "id": "/subscriptions/.../storageAccounts/stsecopslog01/managementPolicies/default",# "lastModifiedTime": "2026-07-13T10:02:31+00:00",# "name": "DefaultManagementPolicy",# "policy": { "rules": [ { "name": "age-out-db-dumps", ... } ] }# }
When two actions land on the same blob, the cheapest outcome wins: delete beats tier-to-archive, which beats tier-to-cold, which beats tier-to-cool. Rules can also aim at *snapshots* and *previous versions* separately from the base blob. That matters the moment versioning is on, because every overwrite leaves behind a previous version that keeps billing like ordinary data until a rule sweeps it up.
Recoverability: soft delete, versioning, immutability
Tiering answers the cost question. Three sibling features answer a different one: *"someone deleted the wrong thing."* Soft delete is a recycle bin. It keeps deleted blobs recoverable for a window you choose, anywhere from 1 to 365 days. A recycle bin is not a backup, so do not file it as one. Versioning keeps the earlier state every time a blob is overwritten or deleted, so any previous version can be promoted back by its ID. Immutability policies give you *WORM* storage (write once, read many). A time-based retention policy or a legal hold makes blobs impossible to change or delete, and once a time-based policy is *locked*, not even the account owner can shorten it or take it off. That is the guarantee behind rules like SEC 17a-4, the US Securities and Exchange Commission requirement that financial records be kept tamper-proof. In production, soft delete plus versioning is a sane default on any account humans can touch. Immutability stays opt-in for compliance data, precisely because nobody, you included, can talk their way past a locked policy.
# One call flips soft delete, versioning, and last-access tracking# (the tracking is what unlocks daysAfterLastAccessTimeGreaterThan rules)az storage account blob-service-properties update \--account-name stsecopslog01 --resource-group rg-storage-prod \--enable-delete-retention true --delete-retention-days 14 \--enable-versioning true \--enable-last-access-tracking true# {# "deleteRetentionPolicy": { "days": 14, "enabled": true },# "isVersioningEnabled": true,# "lastAccessTimeTrackingPolicy": { "enable": true, "trackingGranularityInDays": 1 },# ...# }
Exam signals and production defaults
For AZ-104 (the exam code for Microsoft Azure Administrator Associate), the mechanical facts carry the questions. Minimum stays: Cool 30 days, Cold 90, Archive 180. Rehydration timings: Standard up to 15 hours, High under 1 hour for blobs below 10 GB. Archive is per-blob only, offline, block-blob only, and not supported on zone-redundant accounts (ZRS, GZRS, RA-GZRS: zone-redundant storage, the geo-redundant version of it, and the read-access variant), a favorite cross-question with the redundancy lesson. Lifecycle questions hang on three points. The engine runs on the platform's schedule, up to 24 hours for a policy to take effect, with no on-demand trigger. Last-access rules need tracking enabled first. And the policy attaches to the *account*, never to a single container.
Two habits pay off in production straight away. First, authenticate the data plane with --auth-mode login and RBAC (role-based access control) roles such as *Storage Blob Data Contributor* instead of account keys. An account key is a skeleton key: whoever holds it gets everything, and the audit log cannot tell you who that was. A role assignment is scoped to one identity, shows up in logs, and can be revoked on its own. Second, treat every new account as unfinished until soft delete, versioning and at least a rough lifecycle rule are in place, because blob costs creep upward quietly as data piles on. Blobs cover unstructured objects sitting behind a web address. Plenty of workloads want a real file share instead, with SMB (Server Message Block, the file-sharing protocol Windows speaks), mapped drive letters and integrated backup. That is Azure Files, and it is next.
One point from that list deserves pinning down, because it explains why immutability exists at all. Ransomware crews go after the backups first. Soft delete and versioning cover the colleague who overwrote the wrong file at 4pm on a Friday. A locked time-based retention policy covers an attacker holding valid credentials and a delete button, because the platform itself refuses the delete. Tier and retention are separate dials, so an Archive blob under a legal hold can be cheap and untouchable at the same time.
Lifecycle policies are how you stop paying Hot prices for logs nobody opens, though you should not take the savings on faith. Turn on the storage metrics for capacity and transactions, then set blob capacity per tier against the transaction counts over a full month. If a container you moved to Cool is being read all day, the read charges may have eaten the storage savings, and only the numbers will tell you. The same check shows whether Cold is genuinely cheaper for your access pattern or cheaper only on the price list. Keep one more distinction straight for AZ-104: container public access is normally off, and legitimate sharing goes through a SAS (shared access signature, a time-limited signed link) or an RBAC role instead.
Try this
In a lab storage account, create a container, upload a small file, then set an access tier on it and add a lifecycle rule that cools blobs after a few days. List the blob afterwards to confirm the tier actually stuck.
SA=$(az storage account list --query "[0].name" -o tsv)RG=$(az storage account list --query "[0].resourceGroup" -o tsv)az storage container create --account-name $SA -n labdocs --auth-mode loginecho "hello blob" > /tmp/hello.txtaz storage blob upload --account-name $SA -c labdocs -n hello.txt -f /tmp/hello.txt --auth-mode loginaz storage blob set-tier --account-name $SA -c labdocs -n hello.txt --tier Cool --auth-mode loginaz storage blob show --account-name $SA -c labdocs -n hello.txt --auth-mode login --query "{name:name,tier:properties.blobTier}" -o json
$ az storage blob show ... --query "{name:name,tier:properties.blobTier}" -o json{"name": "hello.txt","tier": "Cool"}# Sample output — Hot for frequent read; Cool/Cold/Archive for cheaper idle data.
Takeaway
Blob tiers trade access cost against storage cost. Lifecycle management automates the walk from Hot to Cool to Archive to deleted, so no human has to remember to do it.
Next: write a lifecycle policy JSON that cools blobs after 30 days and deletes them after 365, then run it against non-prod data first and watch what it actually does before you point it at anything that matters.