Azure Blob Storage costs can spiral out of control without proper management. I have seen organizations spend 10x more than necessary simply because they store everything in the Hot tier indefinitely. With lifecycle management policies, you can automatically transition blobs between access tiers (Hot, Cool, Cold, Archive) and delete expired data—reducing storage costs by 70-90% for typical enterprise workloads. This guide provides a comprehensive approach to designing and implementing lifecycle policies that balance cost optimization with business requirements.
Understanding Azure Storage Tiers
Azure Blob Storage offers four access tiers, each optimized for different access patterns:
| Tier | Storage Cost (per GB/month) | Access Cost (per 10K reads) | Minimum Duration | Use Case |
|---|---|---|---|---|
| Hot | $0.0184 | $0.004 | None | Frequently accessed data |
| Cool | $0.01 | $0.01 | 30 days | Infrequent access (backups) |
| Cold | $0.0036 | $0.10 | 90 days | Rarely accessed (compliance) |
| Archive | $0.00099 | $5.00 | 180 days | Long-term retention |
The key insight: Archive tier is 18x cheaper than Hot for storage, but 1250x more expensive for access. Lifecycle policies must account for actual access patterns, not just age.
Designing Lifecycle Policies
A well-designed lifecycle policy considers multiple dimensions:
flowchart LR
Upload["Blob Uploaded (Hot)"] --> Day30["30 Days: Move to Cool"]
Day30 --> Day90["90 Days: Move to Cold"]
Day90 --> Day365["365 Days: Move to Archive"]
Day365 --> Day2555["7 Years: Delete (Compliance)"]
style Upload fill:#E1F5FE,stroke:#0277BD
style Day2555 fill:#FFCDD2,stroke:#C62828
Implementation: Complete Policy Example
Here is a production-ready lifecycle policy that handles multiple scenarios:
{
"rules": [
{
"enabled": true,
"name": "TransitionToArchive",
"type": "Lifecycle",
"definition": {
"filters": {
"blobTypes": ["blockBlob"],
"prefixMatch": ["logs/", "backups/", "audit/"]
},
"actions": {
"baseBlob": {
"tierToCool": {
"daysAfterModificationGreaterThan": 30
},
"tierToCold": {
"daysAfterModificationGreaterThan": 90
},
"tierToArchive": {
"daysAfterModificationGreaterThan": 180
},
"delete": {
"daysAfterModificationGreaterThan": 2555
}
},
"snapshot": {
"delete": {
"daysAfterCreationGreaterThan": 90
}
}
}
}
},
{
"enabled": true,
"name": "CleanupIncompleteUploads",
"type": "Lifecycle",
"definition": {
"filters": {
"blobTypes": ["blockBlob"]
},
"actions": {
"baseBlob": {
"delete": {
"daysAfterLastAccessTimeGreaterThan": 7
}
}
}
}
},
{
"enabled": true,
"name": "DeleteOldVersions",
"type": "Lifecycle",
"definition": {
"filters": {
"blobTypes": ["blockBlob"]
},
"actions": {
"version": {
"tierToCool": {
"daysAfterCreationGreaterThan": 30
},
"delete": {
"daysAfterCreationGreaterThan": 365
}
}
}
}
}
]
}
Deploying with Bicep
For Infrastructure as Code deployments, here is the Bicep equivalent:
resource storageAccount 'Microsoft.Storage/storageAccounts@2022-09-01' = {
name: 'mycompanystorage'
location: resourceGroup().location
sku: { name: 'Standard_LRS' }
kind: 'StorageV2'
properties: {
accessTier: 'Hot'
}
}
resource managementPolicy 'Microsoft.Storage/storageAccounts/managementPolicies@2022-09-01' = {
parent: storageAccount
name: 'default'
properties: {
policy: {
rules: [
{
enabled: true
name: 'LogsToArchive'
type: 'Lifecycle'
definition: {
filters: {
blobTypes: ['blockBlob']
prefixMatch: ['logs/']
}
actions: {
baseBlob: {
tierToCool: { daysAfterModificationGreaterThan: 30 }
tierToArchive: { daysAfterModificationGreaterThan: 90 }
delete: { daysAfterModificationGreaterThan: 2555 }
}
}
}
}
]
}
}
}
Last Access Time Tracking
For truly intelligent tiering based on actual access patterns (not just age), enable Last Access Time Tracking:
az storage account blob-service-properties update \
--account-name myaccount \
--enable-last-access-tracking true
Then modify your policy to use daysAfterLastAccessTimeGreaterThan instead of daysAfterModificationGreaterThan. This ensures actively accessed files stay in Hot tier regardless of age.
Cost Analysis Example
Real-world scenario: 100 TB of log data retained for 7 years.
| Strategy | Annual Cost | Savings |
|---|---|---|
| All Hot (no lifecycle) | $220,800 | Baseline |
| Lifecycle (Hot→Cool→Archive) | $22,000 | 90% |
Key Takeaways
- Implement lifecycle policies from day one—retrofitting is painful
- Use prefix filters to apply different policies to different data types
- Enable Last Access Time Tracking for access-based tiering
- Archive tier is 18x cheaper but has 180-day minimum and slow retrieval
- Delete old versions and snapshots to avoid hidden costs
- Deploy policies via Bicep/Terraform for consistency across environments
Discover more from C4: Container, Code, Cloud & Context
Subscribe to get the latest posts sent to your email.