Theoretical Foundation: Configure Storage Tiers
1. Initial Intuitionβ
Imagine you manage an office with three types of documents: those you use daily stay on your desk (immediate access, but expensive space); those you consult once a month stay in a file cabinet down the hall (a bit slower, but cheaper); and historical documents from 10 years ago stay in an external warehouse (rarely accessed, minimal storage cost, but takes time to retrieve).
Storage tiers in Azure Blob Storage work exactly like this. Azure offers different "storage shelves" with distinct prices and access characteristics. You place each blob on the appropriate shelf according to its usage pattern, paying less for storage when data is rarely accessed and less for access when data is frequently queried.
The central issue is always a balance between storage cost and access cost.
2. Contextβ
2.1 Why storage tiers existβ
Data storage has a fundamental economic problem: data grows forever, but not all data has the same value over time. Today's application log is critical now but probably will never be read again in 2 years. A 2019 invoice needs to exist for regulatory reasons but is rarely accessed.
Without tiers, you would pay the same price for petabytes of historical data as for active data, which would make cloud storage economically unfeasible for many organizations.
2.2 Where tiers applyβ
Storage tiers are an exclusive feature of Azure Blob Storage (including ADLS Gen2). They do not apply to:
- Azure Files (which has its own layers: Transaction Optimized, Hot, Cool)
- Queue Storage
- Table Storage
- Azure Managed Disks
Tiers apply only to Block Blobs. Append Blobs and Page Blobs do not support all layers.
2.3 Two levels of tier configurationβ
This is a frequent point of confusion: tiers can be defined in two different places:
Storage Account level: Defines the default tier for new blobs that don't specify an explicit tier. Can be Hot or Cool (not Archive).
Individual blob level: Each blob can have a different tier from the account default. This configuration overrides the account default for that specific blob.
3. Building the Conceptsβ
3.1 The four tiersβ
Azure Blob Storage offers four access tiers for Block Blobs:
Hot:
- Optimized for frequently accessed data
- Higher storage cost per GB
- Lower cost for read and write operations
- Immediate access (milliseconds)
- Default for new Storage Accounts
Cool:
- Optimized for infrequently accessed data
- Lower storage cost than Hot
- Higher operation cost than Hot
- Immediate access (milliseconds)
- Data must remain for at least 30 days (early deletion penalty)
Cold:
- Intermediate tier between Cool and Archive
- Lower storage cost than Cool
- Immediate access (milliseconds)
- Data must remain for at least 90 days (early deletion penalty)
Archive:
- Optimized for rarely or never accessed data
- Lowest storage cost available in Azure
- Access requires rehydration (process that can take hours)
- Data must remain for at least 180 days (early deletion penalty)
- The blob is offline in this tier (cannot be read directly)
3.2 Early Deletion Penaltyβ
Each tier has an expected minimum storage duration. If you remove or move a blob before this period, you are charged for the remaining time:
| Tier | Minimum period | Penalty if deleted before |
|---|---|---|
| Hot | None | None |
| Cool | 30 days | Charged for remaining days to 30 |
| Cold | 90 days | Charged for remaining days to 90 |
| Archive | 180 days | Charged for remaining days to 180 |
Practical example: You move a blob to Archive and 30 days later decide to rehydrate it to Hot and delete it. You will be charged for 150 days of Archive storage (the minimum 180 days minus the 30 already elapsed).
3.3 Archive: offline behaviorβ
The Archive tier is fundamentally different from the others. When a blob is in Archive, it doesn't exist on "online" media. It's on tape storage or very low-cost media. To access it:
- You initiate rehydration (hydration): request that the blob be moved from Archive to Hot or Cool.
- Azure processes the rehydration with one of two priorities:
- Standard: 1 to 15 hours (no additional cost)
- High: less than 1 hour for blobs up to 10 GB (significant additional cost)
- After rehydration, the blob becomes normally available in the destination tier.
Non-obvious behavior: There's an alternative to traditional rehydration. You can use the
Copy Bloboperation to copy a blob from Archive directly to a new blob in Hot or Cool, without moving the original. The original blob remains in Archive, and the copy becomes available when the copy/rehydration operation completes. This is useful when you want to keep the file in Archive and just do a one-time read.
3.4 The relationship between account tier and blob tierβ
The account tier is just the default. Each blob can have its own tier defined independently.
3.5 Availability by account typeβ
Not all tiers are available in all Storage Account types:
| Tier | Standard GPv2 | Premium Block Blob | Standard GPv1 |
|---|---|---|---|
| Hot | Yes | Hot only | Yes |
| Cool | Yes | No | No |
| Cold | Yes | No | No |
| Archive | Yes | No | No |
Why GPv2 is the recommended default: It's the only type that supports all four tiers. Premium accounts have superior performance but lose cost flexibility via tiers.
4. Structural View: Cost vs Accessβ
The arrow represents the direction of decreasing storage cost and increasing access cost.
5. Practical Operationβ
5.1 Changing a blob's tier individuallyβ
Tier change is a metadata operation (except for Archive, which is offline). The Set Blob Tier operation instructs the service to move the blob to the new layer.
From Hot/Cool/Cold to Archive: The blob becomes offline progressively (may take a few hours for the process to complete internally).
From Archive to anything: Requires rehydration, which is an asynchronous process.
Between Hot, Cool and Cold: Immediate transition.
5.2 Lifecycle Management: tier automationβ
In practice, you don't change tiers manually blob by blob. You define Lifecycle Management Policies that do this automatically based on time rules.
A lifecycle policy defines rules with:
- Filters: Which blobs the rule applies to (by type, container, prefix, creation date)
- Actions: What to do (move to Cool, Cold, Archive, delete)
- Conditions: When to do it (after X days since modification, creation, or last access)
5.3 Last Access Time Trackingβ
By default, lifecycle policies base their conditions on the blob's last modification date. However, a blob may not be modified but be frequently read (e.g., a static report that many people access).
Azure offers Last Access Time Tracking: when enabled, the system records the last time the blob was read, not just modified. Lifecycle policies can then use daysAfterLastAccessTimeGreaterThan to make decisions based on actual access.
Cost of Last Access Time Tracking: Enabling this feature adds a small transaction overhead on each blob read. Evaluate the additional cost versus the benefit of more precise tiering.
# Enable Last Access Time Tracking
az storage account blob-service-properties update \
--account-name myaccount \
--resource-group myRG \
--enable-last-access-tracking true
6. Implementation Methodsβ
6.1 Azure Portalβ
Changing a blob's tier individually:
Storage Account > Containers > [container] > [blob] > Change tier
The portal presents a dropdown with available options and informs the rehydration priority if the blob is in Archive.
Configuring Lifecycle Management Policy:
Storage Account > Data Management > Lifecycle Management > Add rule
The portal offers a visual interface to build rules with filters and actions, without needing to write JSON.
Limitations: Doesn't allow bulk tier changes via portal (only blob by blob).
6.2 Azure CLIβ
Changing a blob's tier:
# Hot to Cool
az storage blob set-tier \
--account-name myaccount \
--container-name backups \
--name backup-2024-01.bak \
--tier Cool \
--auth-mode login
# Any layer to Archive
az storage blob set-tier \
--account-name myaccount \
--container-name backups \
--name backup-2022-01.bak \
--tier Archive \
--auth-mode login
# Rehydration from Archive to Hot (Standard priority)
az storage blob set-tier \
--account-name myaccount \
--container-name backups \
--name backup-2022-01.bak \
--tier Hot \
--rehydrate-priority Standard \
--auth-mode login
# Rehydration with High priority (faster, more expensive)
az storage blob set-tier \
--account-name myaccount \
--container-name backups \
--name backup-2022-01.bak \
--tier Hot \
--rehydrate-priority High \
--auth-mode login
Checking rehydration status:
az storage blob show \
--account-name myaccount \
--container-name backups \
--name backup-2022-01.bak \
--auth-mode login \
--query "properties.archiveStatus"
The archiveStatus field returns:
null: blob is not in Archive nor in rehydrationrehydrate-pending-to-hot: rehydration to Hot in progressrehydrate-pending-to-cool: rehydration to Cool in progress
6.3 Configuring Lifecycle Management via CLIβ
# Create policy from JSON file
az storage account management-policy create \
--account-name myaccount \
--resource-group myRG \
--policy @lifecycle-policy.json
Example lifecycle-policy.json file:
{
"rules": [
{
"name": "backup-tiering",
"enabled": true,
"type": "Lifecycle",
"definition": {
"filters": {
"blobTypes": ["blockBlob"],
"prefixMatch": ["backups/"]
},
"actions": {
"baseBlob": {
"tierToCool": {
"daysAfterModificationGreaterThan": 30
},
"tierToCold": {
"daysAfterModificationGreaterThan": 90
},
"tierToArchive": {
"daysAfterModificationGreaterThan": 180
},
"delete": {
"daysAfterModificationGreaterThan": 2555
}
},
"snapshot": {
"tierToArchive": {
"daysAfterCreationGreaterThan": 90
},
"delete": {
"daysAfterCreationGreaterThan": 365
}
},
"version": {
"tierToArchive": {
"daysAfterCreationGreaterThan": 90
},
"delete": {
"daysAfterCreationGreaterThan": 365
}
}
}
}
}
]
}
6.4 Using Last Access Time in lifecycle policyβ
{
"rules": [
{
"name": "access-based-tiering",
"type": "Lifecycle",
"definition": {
"filters": {
"blobTypes": ["blockBlob"]
},
"actions": {
"baseBlob": {
"tierToCool": {
"daysAfterLastAccessTimeGreaterThan": 30
},
"tierToArchive": {
"daysAfterLastAccessTimeGreaterThan": 180
}
}
}
}
}
]
}
6.5 Azure PowerShellβ
$ctx = New-AzStorageContext `
-StorageAccountName "myaccount" `
-UseConnectedAccount
# Change blob tier
$blob = Get-AzStorageBlob `
-Container "backups" `
-Blob "backup-2024-01.bak" `
-Context $ctx
$blob.ICloudBlob.SetStandardBlobTier("Cool")
# Change account default tier
Set-AzStorageAccount `
-ResourceGroupName "myRG" `
-Name "myaccount" `
-AccessTier Cool
6.6 Bicep: configuring lifecycle policyβ
resource lifecyclePolicy 'Microsoft.Storage/storageAccounts/managementPolicies@2023-01-01' = {
name: '${storageAccount.name}/default'
properties: {
policy: {
rules: [
{
name: 'backup-tiering'
enabled: true
type: 'Lifecycle'
definition: {
filters: {
blobTypes: ['blockBlob']
prefixMatch: ['backups/']
}
actions: {
baseBlob: {
tierToCool: { daysAfterModificationGreaterThan: 30 }
tierToArchive: { daysAfterModificationGreaterThan: 180 }
delete: { daysAfterModificationGreaterThan: 2555 }
}
}
}
}
]
}
}
}
7. Control and Securityβ
7.1 Permissions for tier changesβ
Changing a blob's tier is a data plane operation. Requires:
| Auth method | Required permission |
|---|---|
| Azure AD (RBAC) | Storage Blob Data Contributor or Owner |
| Storage Account Key | Full access |
| SAS token | w (write) permission on the blob |
Important point: The
Set Blob Tieroperation is considered a write on the blob (modifies its metadata). A SAS with onlyr(read) permission cannot change the tier.
7.2 Permissions for Lifecycle Management Policyβ
Lifecycle Management Policy is a control plane configuration of the Storage Account. Requires:
| Role | Can create/edit policy? |
|---|---|
| Storage Account Contributor | Yes |
| Owner | Yes |
| Storage Blob Data Contributor | No |
| Reader | No |
Note that Storage Blob Data Contributor cannot create lifecycle policies. A control plane role is required.
7.3 Security considerations with Archiveβ
Data in Archive stays on long-term media. Before archiving sensitive data, consider:
- Encryption at rest remains active in Archive (AES-256).
- If using Customer Managed Keys (CMK), key revocation makes data in Archive also inaccessible.
- The rehydration process doesn't bypass any firewall configuration or Private Endpoint.
8. Decision Makingβ
8.1 Which tier for each situationβ
| Situation | Recommended tier | Reason |
|---|---|---|
| Active production application data | Hot | Frequent access, minimal latency |
| Last 30 days backups | Hot or Cool | Occasional access for restore |
| Last 90 days audit logs | Cool | Rare access, but possible |
| Regulatory data 1 to 7 years | Cold or Archive | Very rare access, but mandatory retention |
| Historical backups older than 6 months | Archive | Rarely accessed, minimal cost |
| Website assets served via CDN | Hot | Frequent access by end users |
| Rarely used ML datasets | Cold | Sporadic training |
| 10-year compliance data | Archive + Immutability | Lowest cost + regulatory protection |
| Yesterday's surveillance videos | Hot | May be accessed for investigation |
| 6-month-old surveillance videos | Archive | Rarely accessed |
8.2 Rehydration: Standard vs High Priorityβ
| Situation | Priority | Reason |
|---|---|---|
| Backup restore for critical disaster | High | Time is critical, cost is secondary |
| Planned access to historical data | Standard | Lower cost, hours of latency is acceptable |
| Regulatory audit with weeks deadline | Standard | No urgency, significant savings |
| Active security incident investigation | High | Every hour matters |
8.3 Last Access Time Tracking: when to enableβ
| Situation | Enable? | Reason |
|---|---|---|
| Blobs with variable access pattern | Yes | Tiering based on actual access, not modification |
| Write-once blobs (logs, backups) | Not necessarily | Modification and access coincide at upload |
| Account with high read volume | Evaluate cost | Transaction overhead per read may exceed savings |
| Account with few accesses but varied data | Yes | Precise tiering with minimal overhead |
9. Best Practicesβ
- Configure Lifecycle Management Policies as first action when creating Storage Accounts with data that has defined lifecycle. Don't wait to accumulate data to then define rules.
- Use prefixes to segment data with different lifecycles within the same container. For example:
logs/app/,logs/audit/,backups/daily/,backups/monthly/allow different policies per prefix. - Include actions on snapshots and versions in lifecycle policies. Forgetting to delete old snapshots is a common source of unexpected costs.
- Test lifecycle policies in a test container with manipulated dates before applying to production. Policies are executed once daily and the first cycle may take 24-48h after creation.
- Avoid Archive for data that may be accessed within 180 days. Early deletion penalty and High Priority rehydration cost may exceed storage savings.
- Use
daysAfterLastAccessTimeGreaterThaninstead ofdaysAfterModificationGreaterThanfor data that is frequently read but rarely modified (e.g., static reports). - Monitor
BlobCapacityby tier to validate policies are working and tier distribution is as expected. - Consider transaction costs when designing tiers for high-volume workloads. For many small requests, transaction costs in Cool may exceed storage savings.
10. Common Errorsβ
| Error | Why it happens | How to avoid |
|---|---|---|
| Unexpected cost when moving blobs from Archive before 180 days | Early deletion penalty not considered | Calculate TCO including penalties before archiving |
| Blob in Archive cannot be read after rehydration | Rehydration still in progress | Check archiveStatus before attempting to read |
| Lifecycle policy doesn't apply to existing blobs on first day | Policies have up to 48h delay after creation | Create policy in advance; wait for complete cycle |
| Snapshots and versions remain in Hot after lifecycle policy | Policy doesn't include actions for snapshot and version | Always include snapshot and version sections in policy |
| Last Access Time Tracking cost exceeds savings | Account with high read volume | Calculate overhead before enabling |
| Data in Cool deleted before 30 days | Short lifecycle data moved to Cool | Appropriate tier for actual data lifecycle |
| Archive not available in Premium account | Premium doesn't support Archive | Use Standard GPv2 for data requiring Archive |
| High Priority rehydration not available for blobs > 10 GB | Size limit for High Priority | Use Standard for large blobs or split into smaller parts |
11. Operation and Maintenanceβ
11.1 Monitoring tier distributionβ
In Azure Monitor, filter metrics by BlobCapacity with the Tier dimension:
az monitor metrics list \
--resource <storage-account-id> \
--metric BlobCapacity \
--dimension Tier \
--interval PT1H
This returns capacity separated by Hot, Cool, Cold, and Archive, allowing validation that lifecycle policies are moving data as expected.
11.2 Checking lifecycle policy statusβ
# View current policy
az storage account management-policy show \
--account-name myaccount \
--resource-group myRG
# View last policy execution
az storage account management-policy show \
--account-name myaccount \
--resource-group myRG \
--query "lastModifiedTime"
Lifecycle policies are executed once daily. There's no detailed log of which blobs were moved in each execution (use Change Feed or Diagnostic Logs for granular tracking).
11.3 Important limits and behaviorsβ
| Aspect | Detail |
|---|---|
| Lifecycle policy execution frequency | Once daily (approximately) |
| Delay after policy creation | Up to 48 hours for first execution |
| Maximum rules per lifecycle policy | 100 |
| High Priority rehydration: maximum size | 10 GB per blob |
| Standard rehydration: estimated time | 1 to 15 hours |
| Cancel ongoing rehydration | Possible: move blob back to Archive |
| Archive available in which regions | Almost all regions; check specific availability |
| Account default tier: options | Only Hot or Cool (not Cold or Archive) |
12. Integration and Automationβ
12.1 Azure Data Factory with tiersβ
Azure Data Factory pipelines that process Blob Storage data can define destination tier directly in the copy activity:
{
"sink": {
"type": "BlobSink",
"blobWriterAddHeader": false,
"writeBehavior": "insert"
},
"storeSettings": {
"type": "AzureBlobStorageWriteSettings",
"blockBlobTier": "Cool"
}
}
12.2 Automation with Azure Functions and Event Gridβ
For conditional tiering based on business logic (not just time):
import azure.functions as func
from azure.storage.blob import BlobServiceClient
def main(event: func.EventGridEvent):
blob_url = event.get_json()['url']
# Business logic: if blob is larger than 1GB, move to Cool
client = BlobServiceClient.from_connection_string(conn_str)
blob_client = client.get_blob_client(container="data", blob=blob_name)
props = blob_client.get_blob_properties()
if props.size > 1_073_741_824: # 1 GB
blob_client.set_standard_blob_tier("Cool")
12.3 Monitoring Archive with Azure Monitor Alertsβ
Configure alerts to detect when Archive volume grows faster than expected (possible lifecycle policy bug):
az monitor metrics alert create \
--name "archive-growth-alert" \
--resource-group myRG \
--scopes <storage-account-id> \
--condition "avg BlobCapacity > 1000000000000" \
--condition-dimension Tier=Archive \
--window-size 1d \
--action myActionGroup
13. Final Summaryβ
Essential concepts:
- Storage tiers balance storage cost against access cost: Hot is expensive to store but cheap to access; Archive is cheap to store but expensive and slow to access.
- There are four tiers for Block Blobs in Standard GPv2: Hot, Cool, Cold and Archive.
- The tier can be defined at account level (default for new blobs) or individual blob level (overrides account default).
- Archive is the only offline tier: blobs cannot be read without prior rehydration.
Critical differences:
- Cool vs Cold vs Archive: Cool = 30-day minimum, immediate access. Cold = 90-day minimum, immediate access. Archive = 180-day minimum, access with hours of wait.
- Standard vs High rehydration: Standard takes 1-15 hours with no extra cost. High takes less than 1 hour with additional cost and only for blobs up to 10 GB.
- daysAfterModificationGreaterThan vs daysAfterLastAccessTimeGreaterThan: The first counts since last write. The second (requires Last Access Time Tracking) counts since last read or write.
- Control plane lifecycle policy: Only roles like Storage Account Contributor can create/edit policies. Storage Blob Data Contributor doesn't have this permission.
What needs to be remembered:
- Archive is not available in Premium Block Blob accounts (only Standard GPv2).
- Early deletion penalty is charged if blob is deleted or moved before the tier's minimum period.
- Lifecycle policies are executed once daily and may take up to 48 hours after creation for first execution.
- Always include actions on snapshots and versions in lifecycle policies, not just on the base blob.
- Storage Account default tier can only be Hot or Cool; never Cold or Archive.
- Rehydration can be canceled by moving the blob back to Archive while still processing.