Tiers in one table
| Tier | Storage price | Access cost | Minimum days (early deletion charge) | Access |
|---|---|---|---|---|
| Hot | Highest | Lowest | None | Immediate |
| Cool | Lower | Higher | 30 | Immediate |
| Cold | Lower still | Higher still | 90 | Immediate |
| Archive | Lowest | Highest + rehydration | 180 | Offline: rehydrate first (hours) |
Check current prices for your region and redundancy. The point: colder tiers trade cheap storage for expensive reads.
1. Know your data
Turn on blob inventory (daily or weekly CSV/Parquet report) and query it:
-- e.g. with Synapse serverless / Databricks / DuckDB over the inventory files
SELECT split_part(Name, '/', 1) AS top_folder, AccessTier,
COUNT(*) AS blobs, SUM("Content-Length") / 1e12 AS TB,
MIN("Last-Modified") AS oldest
FROM inventory
GROUP BY 1, 2 ORDER BY TB DESC;
Questions to answer per container/prefix: how big, how old, how often read (storage account read transaction metrics by API, or last-access tracking), and does a retention requirement exist?
2. Enable last-access tracking (optional)
az storage account blob-service-properties update -g rg-data --account-name stlogs01 \
--enable-last-access-tracking true
Rules can then use daysAfterLastAccessTimeGreaterThan, which is useful when "old" doesn't mean "unused". Last access updates are recorded at most once per 24 hours.
3. Write the lifecycle policy
{
"rules": [
{
"name": "app-logs",
"enabled": true,
"type": "Lifecycle",
"definition": {
"filters": { "blobTypes": ["blockBlob"], "prefixMatch": ["logs/"] },
"actions": {
"baseBlob": {
"tierToCool": { "daysAfterModificationGreaterThan": 30 },
"tierToCold": { "daysAfterModificationGreaterThan": 90 },
"delete": { "daysAfterModificationGreaterThan": 400 }
},
"snapshot": { "delete": { "daysAfterCreationGreaterThan": 90 } },
"version": { "delete": { "daysAfterCreationGreaterThan": 90 } }
}
}
},
{
"name": "exports-archive",
"enabled": true,
"type": "Lifecycle",
"definition": {
"filters": { "blobTypes": ["blockBlob"], "prefixMatch": ["exports/yearly/"] },
"actions": { "baseBlob": { "tierToArchive": { "daysAfterModificationGreaterThan": 180 } } }
}
}
]
}
az storage account management-policy create -g rg-data --account-name stlogs01 --policy @policy.json
The policy runs in the background (typically once a day). The first run on a large account can take a while.
4. Avoid the traps
| Trap | Avoid by |
|---|---|
| Early deletion fees | Don't delete/move blobs before the tier's minimum days |
| Archive reads take hours | Archive only data you can wait for; test a rehydration |
| Many tiny blobs | Per-blob transaction cost of tier changes can exceed savings; pack small files (zip/parquet) first |
| Versions and snapshots grow silently | Include version and snapshot actions |
| Cool data read daily | Reads cost more than you save; check read metrics first |
| Archive isn't available on ZRS, GZRS or RA-GZRS accounts | Check the account's redundancy before planning archive rules |
5. Set the default tier sensibly
For accounts that mostly receive write-once data (backups, exports), set the account default access tier to Cool, or upload directly to a tier:
az storage blob upload --account-name stexports01 -c exports -n 2026/10/data.parquet -f data.parquet --tier Cold --auth-mode login
6. Clean up what isn't data
- Incomplete uploads and abandoned containers from old projects.
- Soft-deleted blobs retained longer than needed (soft delete retention is a setting).
- Old diagnostic containers (
insights-logs-*) in accounts that also go to Log Analytics.
7. Measure
Track capacity per tier (BlobCapacity metric split by Tier) and the storage line in Cost Management monthly. Expect savings to show up gradually as rules move data.
Caution
Lifecycle delete actions are permanent once soft delete retention passes. Review prefixes with the data owner and start with tiering-only rules; add delete after a cycle of observation.
Checklist
- Blob inventory reviewed by prefix, age and tier
- Retention requirements confirmed with owners
- Lifecycle rules for base blobs, versions, snapshots
- Small-file and read-frequency traps checked
- Default tiers set for write-once accounts
- Capacity per tier tracked monthly