Skip to main content
Azure · lesson 4 of 10
Azure beginner Lesson 4 of 10

Azure Blob Storage Fundamentals

Create a storage account and container, upload and download a blob with az storage blob, and compare hot, cool, and archive access tiers.

By SkillByExample · Updated

azure storage blob-storage

Blob Storage is Azure’s object store: a storage account provides the namespace and billing boundary, containers inside it group blobs the way folders group files, and each blob can sit in a different access tier that trades storage cost for read cost and speed.

Azure’s local-emulator story for Blob Storage is stronger than for most services: Azurite implements the same Blob, Queue, and Table APIs against a process on your machine, so development against blob storage doesn’t require the cloud. This lesson uses a real account so the tier behavior (especially archive rehydration) is accurate — Azurite doesn’t fully model tier-transition timing.

Creating the storage account and a container

Storage account names must be globally unique across all of Azure, lowercase, and alphanumeric only — hence the numeric suffix.

az storage account create \
  --resource-group learn-rg \
  --name learnstorage482 \
  --location eastus \
  --sku Standard_LRS \
  --kind StorageV2
$ az storage account create --resource-group learn-rg --name learnstorage482 --location eastus --sku Standard_LRS --kind StorageV2
{
  "id": "/subscriptions/3b1f9c2a-6d4e-4a7b-9c11-2f5e8a0b7d33/resourceGroups/learn-rg/providers/Microsoft.Storage/storageAccounts/learnstorage482",
  "kind": "StorageV2",
  "location": "eastus",
  "name": "learnstorage482",
  "primaryEndpoints": {
    "blob": "https://learnstorage482.blob.core.windows.net/",
    "queue": "https://learnstorage482.queue.core.windows.net/",
    "table": "https://learnstorage482.table.core.windows.net/"
  },
  "provisioningState": "Succeeded",
  "sku": {
    "name": "Standard_LRS",
    "tier": "Standard"
  }
}

Standard_LRS (locally redundant storage) keeps three copies within one datacenter — the cheapest redundancy option, fine for this lesson. StorageV2 is the general-purpose account kind that supports blobs, tiers, and lifecycle management together.

az storage container create \
  --account-name learnstorage482 \
  --name reports \
  --auth-mode login
$ az storage container create --account-name learnstorage482 --name reports --auth-mode login
{
  "created": true
}

--auth-mode login authorizes the request using your own Azure AD identity via RBAC, rather than the storage account’s access key — the safer default once you have a Storage Blob Data Contributor role assignment, which avoids passing a key around at all.

Uploading and downloading a blob

echo "quarterly totals: 41205.50" > q3-summary.txt

az storage blob upload \
  --account-name learnstorage482 \
  --container-name reports \
  --name q3-summary.txt \
  --file q3-summary.txt \
  --auth-mode login
$ az storage blob upload --account-name learnstorage482 --container-name reports --name q3-summary.txt --file q3-summary.txt --auth-mode login
Finished[#############################################################] 100.0000%
{
  "etag": "\"0x8DBB3F2A9E1C4D0\"",
  "lastModified": "2026-09-12T14:22:07+00:00"
}
az storage blob list \
  --account-name learnstorage482 \
  --container-name reports \
  --auth-mode login \
  --output table
$ az storage blob list --account-name learnstorage482 --container-name reports --auth-mode login --output table
Name             Blob Type    Blob Tier    Length    Content Type              Last Modified
---------------  -----------  -----------  --------  ------------------------  -------------------------
q3-summary.txt   BlockBlob    Hot          27        text/plain                2026-09-12T14:22:07+00:00

A newly uploaded blob defaults to the account’s configured tier — Hot here, since that’s learnstorage482’s default access tier.

az storage blob download \
  --account-name learnstorage482 \
  --container-name reports \
  --name q3-summary.txt \
  --file q3-summary-downloaded.txt \
  --auth-mode login
$ az storage blob download --account-name learnstorage482 --container-name reports --name q3-summary.txt --file q3-summary-downloaded.txt --auth-mode login
Finished[#############################################################] 100.0000%
{
  "name": "q3-summary.txt"
}

Access tiers: hot, cool, and archive

az storage blob set-tier \
  --account-name learnstorage482 \
  --container-name reports \
  --name q3-summary.txt \
  --tier Archive \
  --auth-mode login
$ az storage blob set-tier --account-name learnstorage482 --container-name reports --name q3-summary.txt --tier Archive --auth-mode login
az storage blob download \
  --account-name learnstorage482 \
  --container-name reports \
  --name q3-summary.txt \
  --file q3-summary-again.txt \
  --auth-mode login
$ az storage blob download --account-name learnstorage482 --container-name reports --name q3-summary.txt --file q3-summary-again.txt --auth-mode login
ERROR: This operation is not permitted on an archived blob.

The blob still exists and still lists normally — only reading its content is blocked. Moving it back requires rehydration:

az storage blob set-tier \
  --account-name learnstorage482 \
  --container-name reports \
  --name q3-summary.txt \
  --tier Hot \
  --rehydrate-priority Standard \
  --auth-mode login

az storage blob show \
  --account-name learnstorage482 \
  --container-name reports \
  --name q3-summary.txt \
  --auth-mode login \
  --query "properties.{tier:blobTier, rehydrateStatus:rehydrationStatus}"
$ az storage blob show --account-name learnstorage482 --container-name reports --name q3-summary.txt --auth-mode login --query "properties.{tier:blobTier, rehydrateStatus:rehydrationStatus}"
{
  "tier": "Archive",
  "rehydrateStatus": "rehydrate-pending-to-hot"
}

rehydrate-pending-to-hot with tier still showing Archive is expected mid-transition — standard-priority rehydration can take up to 15 hours; --rehydrate-priority High is faster and costs more. The download only succeeds once the tier flips to Hot.

Practice

1. Set the storage account's default access tier to Cool and explain what that changes.
az storage account update --name learnstorage482 --resource-group learn-rg --access-tier Cool
$ az storage account update --name learnstorage482 --resource-group learn-rg --access-tier Cool
{
  "accessTier": "Cool",
  "name": "learnstorage482"
}

This only changes the tier assigned to new blobs uploaded without an explicit --tier — existing blobs, including q3-summary.txt, keep whatever tier they’re already on.

2. List blobs filtered by tier to find everything still sitting in Hot.
az storage blob list --account-name learnstorage482 --container-name reports --auth-mode login --query "[?properties.blobTier=='Hot'].name" --output tsv
$ az storage blob list --account-name learnstorage482 --container-name reports --auth-mode login --query "[?properties.blobTier=='Hot'].name" --output tsv
q3-summary.txt

--query runs a JMESPath filter against the JSON before it’s ever turned into a table — useful for scripting cleanup of blobs sitting in the wrong tier.

3. Generate a time-limited shared access signature (SAS) URL for the blob and explain why it's safer than sharing the account key.
az storage blob generate-sas \
  --account-name learnstorage482 \
  --container-name reports \
  --name q3-summary.txt \
  --permissions r \
  --expiry 2026-09-13T00:00:00Z \
  --auth-mode login \
  --as-user
$ az storage blob generate-sas --account-name learnstorage482 --container-name reports --name q3-summary.txt --permissions r --expiry 2026-09-13T00:00:00Z --auth-mode login --as-user
se=2026-09-13T00%3A00%3A00Z&sp=r&spr=https&sv=2024-11-04&sr=b&skoid=7c4d9e2a-1f8b-4a6c-9d3e-5b0a8f7c2d61&sktid=a1e4f6b2-8c3d-4f19-b7e2-5d9c1a0f3e88&skt=2026-09-12T15%3A00%3A00Z&ske=2026-09-13T00%3A00%3A00Z&sks=b&skv=2024-11-04&sig=Xk3mQ9pL7vN2wZ8yT4jH0cS5bA8dE2gV1nX3fY0k3F8%3D

An account key grants full access to every container until it’s rotated; a SAS token grants one permission (r, read-only here) on one blob until one timestamp, and --as-user ties it to your own identity rather than the account key so it can also be revoked via RBAC.

4. Enable soft delete on the storage account so accidental deletes are recoverable.
az storage blob service-properties delete-policy update \
  --account-name learnstorage482 \
  --enable true \
  --days-retained 7
$ az storage blob service-properties delete-policy update --account-name learnstorage482 --enable true --days-retained 7
{
  "enabled": true,
  "days": 7
}

With this on, a deleted blob becomes a soft-deleted one that can be undeleted within 7 days instead of disappearing immediately — the same safety net a recycle bin gives a filesystem.

5. Delete the container and confirm the storage account itself survives.
az storage container delete --account-name learnstorage482 --name reports --auth-mode login
az storage account show --name learnstorage482 --query "provisioningState" --output tsv
$ az storage container delete --account-name learnstorage482 --name reports --auth-mode login
{
  "deleted": true
}
$ az storage account show --name learnstorage482 --query "provisioningState" --output tsv
Succeeded

Deleting a container removes it and every blob inside, but the storage account resource — and its endpoints and access keys — remain, ready to hold new containers.

Next: Virtual Network basics — subnets, an NSG, and debugging a VM that can’t reach the internet.

Frequently Asked Questions

What is the difference between a storage account and a container?
A storage account is the top-level Azure resource that gives you a unique namespace and holds your billing and access settings; a container lives inside it and is roughly equivalent to a top-level folder that holds blobs. One storage account can hold many containers, and access tiers and lifecycle rules can be set per blob or per container within the same account.
Can I run Azure Blob Storage locally without an Azure account?
Yes, with Azurite — Microsoft's official open-source emulator for Blob, Queue, and Table storage. It runs as a local process (or Docker container) and accepts the same connection string shape and SDK calls as a real storage account, which makes it useful for local development and CI, though it doesn't model every feature (like geo-replication or some tier-transition timing).
What's the practical difference between hot, cool, and archive tiers?
They trade storage cost against retrieval cost and speed: hot is cheapest to read and most expensive to store, archive is cheapest to store but data must be rehydrated (a process that can take hours) before it can be read, and cool sits in between with a minimum 30-day storage duration and small retrieval fees. Pick based on how often the data is actually read, not how important it is.
Do I need to rehydrate a blob before I can even see it exists in the archive tier?
No. Listing, metadata, and even downloading the blob's properties work normally on an archived blob — what fails is trying to read its actual content. You call az storage blob set-tier to move it to hot or cool, then wait for rehydration to finish before the download will succeed.