Storage & Databases
Azure Blob Storage, Azure SQL Database and Cosmos DB, and how to choose the right one for your data.
Where does your data actually live?
Every application needs somewhere to put data — uploaded files, user records, product catalogs, logs. Azure's storage and database options span a spectrum from "just a bucket of files" to "a globally distributed database," and picking the right one is one of the most consequential architecture decisions you'll make. This page covers the three you'll meet constantly: Blob Storage, Azure SQL Database, and Cosmos DB.
Azure Blob Storage
Blob Storage is Azure's object storage service — built for storing large amounts of unstructured data: images, videos, backups, log files, PDFs, ML training data, anything that isn't naturally a row in a table. "Blob" simply stands for Binary Large OBject — it's just a name for "a file," stored and retrieved as a whole rather than queried in parts.
Blob Storage has its own three-level hierarchy, similar in spirit to the resource-group hierarchy from the introduction page:
Storage Account (the top-level container — has a globally unique name)
└── Container (like a folder / bucket — groups related blobs)
└── Blob (the actual file)
A storage account is the billing and access boundary — it has a name that must be unique across all of Azure (since it forms part of the storage account's URL), and it can hold blobs, but also other storage services like file shares and queues. A container is roughly analogous to a folder, though blob storage is technically a flat namespace — folders you see in the portal are really just blob names containing /, simulated for convenience.
A real example: uploading a file
# 1. Create a storage account (name must be globally unique, lowercase, no dashes)
az storage account create \
--name learningstorage2026 \
--resource-group learning-rg \
--location eastus \
--sku Standard_LRS
# 2. Create a container inside it
az storage container create \
--account-name learningstorage2026 \
--name uploads \
--auth-mode login
# 3. Upload a local file into that container
az storage blob upload \
--account-name learningstorage2026 \
--container-name uploads \
--name profile-photo.jpg \
--file ./profile-photo.jpg \
--auth-mode login
That file is now stored redundantly (Standard_LRS means "locally redundant storage" — three synchronous copies within one datacenter) and reachable at a URL like https://learningstorage2026.blob.core.windows.net/uploads/profile-photo.jpg — public or private, depending on the container's access level.
Access tiers
Not all data needs to be equally "ready." Blob Storage lets you assign each blob (or the whole account) an access tier that trades retrieval speed for storage cost:
| Tier | Best for | Storage cost | Retrieval |
|---|---|---|---|
| Hot | Data accessed frequently (active user uploads, a website's images) | Highest | Instant |
| Cool | Data accessed infrequently, kept for at least 30 days (monthly backups) | Lower | Instant, small retrieval fee |
| Cold | Accessed rarely, kept for at least 90 days | Lower still | Instant, higher retrieval fee |
| Archive | Rarely-ever accessed, kept for at least 180 days (compliance archives, old logs) | Lowest | Hours — must be explicitly "rehydrated" first |
The intuition: it's like the difference between keeping a box in your closet (Hot — instantly available, but your closet space is precious), a storage unit across town (Cool/Cold — cheaper, but you have to go get it), and a document you shipped off to a long-term archive facility (Archive — cheapest, but it takes real time to get it back). Picking the wrong tier is a very common (and very fixable) source of overpaying — a photo gallery no one has viewed in two years belongs in Cool or Archive, not Hot.
Azure SQL Database
Azure SQL Database is a fully managed, relational database — a PaaS version of Microsoft SQL Server. You define tables, columns, types, and relationships, and query with familiar T-SQL:
CREATE TABLE Students (
Id INT IDENTITY PRIMARY KEY,
Name NVARCHAR(100) NOT NULL,
Email NVARCHAR(255) UNIQUE NOT NULL,
EnrolledOn DATE NOT NULL
);
SELECT Name, Email FROM Students WHERE EnrolledOn > '2026-01-01';
Azure handles patching, backups, high availability, and point-in-time restore for you — you focus purely on schema and queries. It's the right fit whenever your data is naturally structured, relational, and transactional: things like orders, inventory, invoices, and user accounts, where rows relate to other rows (a Student has many Enrollments, which relate to Course rows) and you need strong consistency guarantees — an order total must never be wrong because two writes happened at once.
Azure Cosmos DB
Cosmos DB is Azure's globally distributed, multi-model NoSQL database, built for a very different set of priorities: massive scale, very low and predictable latency (single-digit milliseconds, guaranteed by an SLA), and the ability to write data from multiple regions around the world at once.
A few things make Cosmos DB distinctive:
- Multiple APIs — the same underlying engine can be queried as if it were a document store (its native "NoSQL/Core" API), a MongoDB-compatible database, a Cassandra-compatible database, or even a graph database (Gremlin API) — letting you pick the data model (and often reuse existing driver code) that best fits your app.
- Schema flexibility — documents in the same container don't need identical fields, which suits data that varies in shape or evolves quickly (a product catalog where different product types have different attributes).
- Tunable consistency — Cosmos DB offers five consistency levels on a spectrum from strong (always read the latest write, at the cost of latency) to eventual (fastest, but a read might briefly return stale data) — letting you choose the trade-off per application instead of getting one fixed answer.
- Global distribution — you can literally check a box to replicate your database to additional regions, and Cosmos DB handles the replication and (if configured) multi-region writes.
Choosing between them
| If you need... | Choose |
|---|---|
| A place to store files, images, videos, or backups | Blob Storage |
| Structured data with relationships, joins, and transactions (orders, accounts, inventory) | Azure SQL Database |
| Massive scale, global low-latency access, or a flexible/evolving schema | Cosmos DB |
| A traditional relational app you're migrating from on-prem SQL Server | Azure SQL Database |
| A mobile/IoT/gaming backend serving users worldwide with strict latency needs | Cosmos DB |
A useful way to frame it: Blob Storage answers "where do I put files?", Azure SQL Database answers "where do I put structured, relational records that need strong consistency?", and Cosmos DB answers "where do I put data that needs to be fast and available everywhere in the world, at any scale, even if the schema isn't fixed?" Many real applications actually use all three at once — user-uploaded photos in Blob Storage, transactional order data in Azure SQL Database, and a fast-read product catalog or session store in Cosmos DB.
Common mistakes
- Storing files inside a relational database. Putting large binary files (images, videos) directly into SQL rows works but is slow and expensive at scale — store the file in Blob Storage and keep only its URL/path in the database row.
- Leaving everything in the Hot access tier. It's the default, and it's easy to forget that rarely-accessed data (old backups, historical logs) is quietly costing more than it needs to in Cool or Archive.
- Choosing Cosmos DB by default because it sounds more "modern." Cosmos DB is excellent for its specific niche (global scale, flexible schema, guaranteed low latency), but it's overkill — and more expensive — for a typical small-to-medium app whose data is naturally relational. Azure SQL Database is the right, boring, reliable default for most transactional apps.
- Forgetting storage account names must be globally unique. Since the name becomes part of a public URL (
<name>.blob.core.windows.net), a name that's already taken anywhere on Azure — by anyone — will be rejected.