
Azure Cosmos DBAuthorCloudBrum editorial teamLast reviewedReading time~12 minLevelBeginner to advanced
Microsoft Azure · Databases · Globally distributed NoSQL database
Cosmos DB is Microsoft’s globally distributed database for JSON data, and the Azure service where you buy throughput directly. Every operation costs request units (RUs), and you either reserve a rate of them or pay for what you use. You choose a partition key that spreads data and traffic, pick one of five consistency levels, and add the Azure regions you want replicas in. The RU bill is the part to watch, because one query that fans out to every partition can cost more than a thousand point reads.
On this page (17 sections)
Mind map: Azure Cosmos DB at a glance
Free to share. The downloaded image includes the CloudBrum link.
Key features (summary)
- Replicated where your users areAdd Azure regions to an account and Cosmos DB copies the data to each and serves reads from the nearest. Writes go to one region, or to all of them if you turn on multi-region writes.
- Throughput measured in RUsA request unit is a blend of CPU, memory and I/O. A point read of a 1 KB item costs about 1 RU, and writes, queries and big items cost more. The response tells you the exact charge, so you can tune with numbers.
- Three ways to buy itProvisioned throughput reserves a fixed RU/s. Autoscale moves between 10 percent and 100 percent of a maximum and bills the highest level used each hour. Serverless has no reservation and bills the RUs you consume.
- Five consistency levelsFrom strong to eventual, with bounded staleness, session and consistent prefix in between. Session, the default, gives each client read-your-writes and suits most applications.
- Partitions by designItems with the same partition key value form a logical partition that can hold up to 20 GB and use up to 10,000 RU/s. Hierarchical partition keys let you split a large tenant over several levels.
- Every property indexedBy default Cosmos DB indexes all properties, so queries work without index planning. An indexing policy lets you leave out paths that are never filtered on, which lowers the RU cost of writes.
- Change feedAn ordered record of inserts and updates per partition. Azure Functions and the change feed processor read it to update views, send messages or feed search, without polling.
- Vector, full-text and hybrid searchA DiskANN-based vector index, full-text search with BM25 ranking and hybrid queries that combine them are built into the NoSQL API, which keeps embeddings next to the documents they describe.
Basic concepts
- Account
- The top-level resource. It holds the region list, the default consistency level, the backup policy, networking and the keys or roles. A subscription can have one free tier account.
- Database and container
- A database groups containers. A container is where items live, and it carries the partition key, the throughput settings and the indexing policy.
- Item
- One JSON document. It needs an id, which must be unique inside its partition, and the property named by the partition key path. Items can be up to 2 MB.
- Partition key
- The property whose value decides which logical partition an item belongs to. It can’t be changed after the container is created, so it needs the most thought of any setting.
- Logical and physical partition
- A logical partition is all items with one partition key value. Cosmos DB places logical partitions on physical partitions and splits them as data and throughput grow, without downtime.
- Request unit (RU)
- The currency of a Cosmos DB bill. Every read, write and query uses some, and the response header x-ms-request-charge shows how many.
- Provisioned, autoscale and serverless
- The three throughput models. Provisioned is a fixed RU/s, with a minimum of 400. Autoscale follows load up to a maximum you set. Serverless bills consumed RUs and has ceilings on storage and throughput.
- Consistency level
- How fresh and ordered a read is: strong, bounded staleness, session, consistent prefix or eventual. Stronger levels cost more RUs per read and add latency across regions.
- Point read
- A read by id and partition key value. It skips the query engine and is the cheapest and fastest way to get one item.
- Indexing policy
- Tells Cosmos DB which paths to index and how. The default indexes everything, and a tighter policy cuts write cost and storage.
- Change feed
- A persistent, ordered log of changes in a container that applications read at their own pace.
- Time to live (TTL)
- A per-container or per-item number of seconds after which Cosmos DB deletes the item. Expiry uses leftover RUs, so a heavily loaded container may delete later.
- Data-plane role
- A role from Cosmos DB’s own role-based access control, such as the built-in Data Reader or Data Contributor, assigned to a Microsoft Entra identity at account, database or container scope.
How to create & configure it
Create an account, a container and keyless access with the Azure CLI
- Write down the access patternsList the reads: one order by ID, all orders of a customer, orders by status. The partition key must be a value present in most of them, with many different values.
- Create the accountPick the region, keep session consistency unless you can name a reason, choose continuous backup, and turn off key-based access so only Microsoft Entra ID works. The first account in a subscription can use the free tier.
- Create a database and a containerSet the partition key path, and start with autoscale so a quiet container costs little and a busy one doesn’t throttle.
- Trim the indexing policyExclude large paths that you never filter or sort on, such as free-text notes. Keep the default for everything else until you have measured.
- Give identities data accessAssign the built-in Data Reader or Data Contributor role to the app’s managed identity at the narrowest scope that works.
- Prefer point reads and single-partition queriesRead by id and partition key, and put the partition key in the WHERE clause. Check the RU charge of each query during development.
- Guard writes with ETagsSend the item’s ETag on a replace, and handle a 412 answer by reading the item again, so two writers can’t silently overwrite each other.
- Watch normalised RU consumption and 429sNormalizedRUConsumption shows the busiest partition’s share of throughput. A high value with a low total means a hot partition key.
- Plan backup, failover and costKnow your restore window, add a second region if downtime is unacceptable, and set a budget alert on the account.
Tip: the partition key and the container’s id rule can’t be changed in place. If the key was a poor choice, create a new container and copy the data over (the change feed makes that painless). See the code references for the same setup as Terraform.
Common issues after configuration
| Symptom | Likely cause | What to check / fix |
|---|---|---|
| HTTP 429, request rate is large | The container used more RU/s than provisioned, or one partition ran hot and used its share | The SDK retries 429s for you, but sustained ones need action. Raise the RU/s or the autoscale maximum, check NormalizedRUConsumption for a hot key, and cut the RU cost of the busy operations. |
| A query costs far more RUs than expected | It ran across all partitions, or the filter couldn’t use the index | Put the partition key in the filter, look at the query metrics, and add or restore an index path that the filter needs. |
| Partition key reached maximum size of 20 GB | One logical partition filled up, for example a tenant or a date used as the key | Choose a key with more values or a hierarchical key, and move the data to a new container. |
| 403 Forbidden on a request that has the right endpoint | Keys are disabled and the identity has no data-plane role, or a firewall or private endpoint blocks the caller | Assign a Cosmos DB data role (a general Azure role is not enough), and check the account’s network settings. |
| 401 Unauthorized, input authorization token can’t serve the request | A key was regenerated, the clock is far off, or the wrong account key is in use | Fetch the key again or move to Entra ID, and correct the system clock. |
| A point read returns 404 for an item that exists | The partition key value in the call doesn’t match the item’s | Pass both the id and the exact partition key value. The same id can exist in other partitions. |
| 409 Conflict on create | An item with that id already exists in that partition | Treat it as already done, or use an upsert if overwriting is intended. |
| 412 Precondition Failed on replace | The item changed since you read it, so the ETag no longer matches | Read the item again, apply the change on the fresh copy and retry. |
| A reader in another region sees old data | The account’s consistency level is weaker than strong, so remote reads can lag | Use session consistency with the session token carried between calls, or choose bounded staleness or strong for that flow. |
| Writes got more expensive after a change | A policy that indexes every property, large items, or a new multi-region write setup multiplied the cost | Trim the indexing policy, shrink items, and compare the RU charge before and after the change. |
| The bill is higher than expected | Provisioned RU/s that is idle, many regions each billed for the RU/s, or autoscale peaks | Check the idle share of RU/s, drop regions you don’t read from, and move quiet containers to autoscale or serverless. |
Use cases: when and where to use it
Good fit
- Applications with users in several regions that need low-latency reads and writes close to them
- Catalogues, profiles, carts and device state stored as JSON with flexible shapes
- Multi-tenant SaaS that gives each tenant a partition key value
- Event and telemetry data read through the change feed
- AI applications that keep embeddings and documents together for vector and hybrid search
- Workloads that need a service-level agreement for latency, availability and consistency
Consider something else
- Relational data, joins and reporting → Azure SQL Database or Azure Database for PostgreSQL
- A MongoDB-compatible database that runs on vCores → Azure DocumentDB, the renamed vCore service
- A cache for hot data → Azure Cache for Redis
- Search across large text collections → Azure AI Search
- Analytics over large data → Azure Synapse Analytics or Microsoft Fabric
- The same job on other clouds → compare Amazon DynamoDB and Firestore
Pros: why consider it?
Why teams choose it
- Replication to any number of Azure regions, with a managed failover option
- Five consistency levels, so each workload can choose its trade-off
- Single-digit-millisecond reads and writes at the 99th percentile for point operations, under the service-level agreement
- Indexing is automatic, so new query shapes don’t need new indexes
- Several APIs, including MongoDB, Cassandra and Table, ease a move from existing code
- Entra ID roles, private endpoints and customer managed keys
Trade-offs to weigh
- The partition key is permanent, and a poor choice means a migration
- Costs follow request units, which takes time to estimate and watch
- A cross-partition query gets more expensive as the container grows
- Throughput is billed in every region that has a replica
- Items are limited to 2 MB and logical partitions to 20 GB
- Joins across containers, and reporting across them, are not what it is for
Common threats, vulnerabilities & risks
| Risk | Severity | Why it matters | Mitigation |
|---|---|---|---|
| Account keys left enabled | High | A leaked key gives full access to every container, and it doesn’t show who used it. | Disable key-based access, use Microsoft Entra ID roles, and rotate any key that still has to exist. |
| Public network access without limits | High | An account reachable from anywhere depends on one credential for its safety. | Use private endpoints or a firewall with named networks, and review the allowed ranges. |
| No point-in-time restore | High | Periodic backup is slow to restore and goes through a support request, so a bad deployment lasts longer. | Use continuous backup with 7 or 30 days, and try a restore into a new account. |
| A poor partition key | Medium | A key with few values or lopsided traffic throttles one partition while the rest sit idle, and hits the 20 GB limit. | Choose a high-cardinality key, test with realistic load, and consider hierarchical keys for large tenants. |
| Unbounded cross-partition queries | Medium | Each such query asks every partition, so its RU cost grows with the data and it can starve other work. | Put the partition key in the filter, review the slowest queries and set a budget on them. |
| Throughput set and forgotten | Medium | A container provisioned at a launch-day rate keeps billing at it every hour. | Use autoscale where load varies, review RU use monthly and lower what is idle. |
| Weak consistency on the wrong data | Medium | Eventual or prefix reads can show stale balances or inventory to a user. | Match the level to the flow. Use session or stronger where a user must see their own change. |
| Large items and wide indexing | Low–Med | Each write of a big item with every property indexed uses many RUs. | Keep items small, exclude unused paths from the index and move blobs to Storage. |
| Single region for critical data | Low–Med | A regional outage takes the application down. | Add a second region, enable service-managed failover and test it. |
Performance optimisation
- Pick a partition key with many distinct values so that requests and storage spread out, and no single logical partition becomes the limit.
- Use point reads (id and partition key) whenever you know the item, because they are the fastest and cheapest operation.
- Keep queries inside one partition by putting the partition key in the filter.
- Use the latest SDK in direct mode, create one client for the whole application, and keep it alive.
- Read from the nearest region by setting the SDK’s preferred regions, and place compute in the same region.
- Trim the indexing policy to the paths you filter and sort on, which makes writes faster and cheaper.
- Keep items small, and put large content in Blob Storage with a link in the item.
- Handle 429 responses with the SDK’s retry settings, and treat sustained throttling as a capacity or key problem, not a retry problem.
Reduce monthly cost
FinOps is the habit of managing cloud spend together with engineering. These are the FinOps checks that matter most for Azure Cosmos DB.
- Use autoscale for variable load and manual throughput for steady load that stays close to the provisioned level.
- Consider serverless for development, test and spiky low-volume workloads.
- Take the free tier (first 1000 RU/s and 25 GB) on one account per subscription for small workloads.
- Reduce RU use with point reads, single-partition queries and a trimmed index.
- Add only the regions you need, since throughput is billed in each one.
- Use reserved capacity for steady provisioned throughput where you can commit to a term.
- Keep 7-day continuous backup unless you need the longer window, which costs extra.
- Use TTL to remove data you don’t need, and shrink the storage bill.
- Review idle containers and databases with shared throughput and merge small ones.
- Tag accounts by team and add a budget alert, so a runaway query shows up the same day.
Figures here come from Microsoft's pricing and documentation pages and published guides, read in October 2026. Rates change with the region and a few sources disagree, so check the live page (see Pricing).
Security optimisation
- Use Microsoft Entra ID and data-plane roles, and disable key-based access once every client has moved to roles.
- Assign the narrowest role and scope, for example Data Reader on one container for a reporting job.
- Reach the account through private endpoints, or limit public access to named networks.
- Use customer managed keys from Azure Key Vault if your policy requires control of the encryption key. Data is encrypted at rest by default.
- Turn on continuous backup and test a restore into a separate account.
- Enable diagnostic logs for data-plane requests and send them to Log Analytics.
- Use resource locks and Azure Policy to stop accounts from being deleted or opened to the internet.
- Keep secrets and card data out of items, or encrypt sensitive properties on the client with Always Encrypted.
- Alert on key regeneration, role assignment changes and failover events.
- Review Microsoft Defender for Cosmos DB findings where it is enabled.
Governance & compliance
Guardrails
- A shared Bicep or Terraform module that creates accounts with continuous backup, keys disabled, private endpoints and tags
- Azure Policy that denies accounts with key-based access or public network access, where that fits your rules
- Naming rules for containers and partition key paths, with the access patterns documented next to the definition
- A review step for new containers, with the partition key choice and the expected RU use
Continuous checks (Azure Policy, Defender for Cloud and your own scripts)
- Azure Policy compliance for key-based access, public access and backup mode
- A scheduled script that lists containers whose provisioned RU/s stays below 10 percent use for a month
- Alerts on NormalizedRUConsumption, TotalRequests with status 429 and replication latency
- An activity log alert for key regeneration, role assignment and failover changes
- A monthly report of containers by RU/s and by storage
Azure Policy can deny or audit account settings, Microsoft Defender for Cloud reports on posture, Azure Monitor and the activity log record changes and metrics, and the Microsoft Service Trust Portal holds compliance reports. Microsoft runs the service, replicates the data and encrypts it at rest. Who gets which role, the partition design, regions, backup choices and what data is stored are yours.
Reduce carbon footprint
- Provision for the load you have: use autoscale or serverless instead of a fixed RU/s that sits idle.
- Replace cross-partition queries with point reads and single-partition queries, which do less work.
- Delete expired data with TTL, and trim the indexing policy to cut storage and write work.
- Add only the regions your users need.
- Pick a region with a cleaner power grid for the account when data rules and latency allow it.
- Microsoft’s Emissions Impact Dashboard reports per subscription, with no separate figure for Cosmos DB, so this page gives none.
Pricing
Purchase options
Provisioned throughput Per 100 RU/s per hour
You pay for the RU/s you reserve, with a minimum of 400 RU/s per container or database, used or not. Reserved capacity lowers the rate for steady use.
Autoscale Highest RU/s each hour
Billing follows the highest RU/s the container reached in each hour. The container scales between 10 percent and 100 percent of the maximum you set, and the rate per RU/s is higher than for manual throughput.
Serverless Per million RUs consumed
No reservation, which suits spiky or small workloads. It has limits on storage and throughput per container.
Storage, backup and regions Per GB-month, plus each added region
Transactional storage is billed per GB. Continuous backup with 7 days is free and 30 days costs extra. Every region repeats the throughput charge.
What you actually pay for
- Provisioned or autoscale RU/s per hour, or the RUs consumed on serverless
- Stored data, and index storage with it
- Continuous backup beyond 7 days, and periodic backups beyond the two free copies
- Throughput in every added region, and in each write region with multi-region writes
- Data transfer between regions and out to the internet
Microsoft lists a free tier of 1000 RU/s and 25 GB for the lifetime of one account per subscription, and rates differ by region. See the official Azure Cosmos DB pricing page and the Azure pricing calculator.
Important code references
A shop: a Cosmos DB account with session consistency, 7-day continuous backup and keys switched off, a database with an autoscale orders container partitioned by customer, a trimmed indexing policy, and a Data Contributor role for one identity. The CLI tab builds it and reads the metrics that show a hot partition; Terraform describes the same resources. The Python tab shows a safe insert, a point read, a single-partition query and an ETag-guarded update, and the C# tab compares what a single-partition query and a cross-partition query cost in RUs. Replace the names and the region with your own.
# Placeholders: replace the names and the region with your own. The account name must be unique worldwide.
RG=rg-cosmos-demo
LOC=centralindia
ACCOUNT=cosmos-shop-$RANDOM
USER_ID=$(az ad signed-in-user show --query id --output tsv)
az group create --name $RG --location $LOC
# 1. The account: session consistency, 7-day continuous backup (the 7-day tier is free) and key-based access switched off,
# so only Microsoft Entra ID can get in. On the first account of a subscription you can add --enable-free-tier true.
az cosmosdb create --name $ACCOUNT --resource-group $RG --locations regionName=$LOC failoverPriority=0 isZoneRedundant=False \
--default-consistency-level Session --backup-policy-type Continuous --continuous-tier Continuous7Days --disable-local-auth true
# 2. A database, and an orders container partitioned by customer. The partition key can't be changed later.
# --max-throughput 1000 is autoscale: it runs between 100 and 1000 RU/s. --ttl -1 turns on TTL for items that carry a ttl value.
az cosmosdb sql database create --account-name $ACCOUNT --resource-group $RG --name shop
cat > indexing.json <<JSON
{"indexingMode": "consistent", "includedPaths": [{"path": "/*"}], "excludedPaths": [{"path": "/notes/*"}, {"path": "/\"_etag\"/?"}]}
JSON
az cosmosdb sql container create --account-name $ACCOUNT --resource-group $RG --database-name shop --name orders \
--partition-key-path /customerId --max-throughput 1000 --idx @indexing.json --ttl -1
# 3. Data access through Entra ID. The ID ending in 0002 is the built-in Data Contributor role, and 0001 is Data Reader.
az cosmosdb sql role assignment create --account-name $ACCOUNT --resource-group $RG --scope "/dbs/shop" \
--principal-id $USER_ID --role-definition-id 00000000-0000-0000-0000-000000000002
# 4. Check what was created, and that the keys are off.
az cosmosdb show --name $ACCOUNT --resource-group $RG \
--query "{consistency: consistencyPolicy.defaultConsistencyLevel, localAuthDisabled: disableLocalAuth, backup: backupPolicy.type}"
# 5. Is one partition running hot? NormalizedRUConsumption is the busiest partition's share of the provisioned throughput.
ACCOUNT_ID=$(az cosmosdb show --name $ACCOUNT --resource-group $RG --query id --output tsv)
az monitor metrics list --resource $ACCOUNT_ID --metric NormalizedRUConsumption --aggregation Maximum --interval PT5M --offset 1h
# 6. How many request units did the orders container use over the last day?
az monitor metrics list --resource $ACCOUNT_ID --metric TotalRequestUnits --aggregation Total --interval PT1H --offset 1d \
--filter "CollectionName eq 'orders'"
# Placeholders: pass in your own names. The values below are examples.
variable "location" {
type = string
default = "centralindia"
}
variable "account_name" {
type = string # unique worldwide, lowercase letters, digits and hyphens
}
variable "app_principal_id" {
type = string # object ID of the managed identity that reads and writes the data
}
provider "azurerm" {
features {}
}
resource "azurerm_resource_group" "cosmos" {
name = "rg-cosmos-demo"
location = var.location
}
resource "azurerm_cosmosdb_account" "shop" {
name = var.account_name
location = azurerm_resource_group.cosmos.location
resource_group_name = azurerm_resource_group.cosmos.name
offer_type = "Standard"
kind = "GlobalDocumentDB"
local_authentication_disabled = true # Microsoft Entra ID is the only way in
consistency_policy {
consistency_level = "Session"
}
geo_location {
location = azurerm_resource_group.cosmos.location
failover_priority = 0
}
backup {
type = "Continuous"
tier = "Continuous7Days"
}
}
resource "azurerm_cosmosdb_sql_database" "shop" {
name = "shop"
resource_group_name = azurerm_resource_group.cosmos.name
account_name = azurerm_cosmosdb_account.shop.name
}
resource "azurerm_cosmosdb_sql_container" "orders" {
name = "orders"
resource_group_name = azurerm_resource_group.cosmos.name
account_name = azurerm_cosmosdb_account.shop.name
database_name = azurerm_cosmosdb_sql_database.shop.name
partition_key_paths = ["/customerId"]
partition_key_version = 2
default_ttl = -1
autoscale_settings {
max_throughput = 1000
}
indexing_policy {
indexing_mode = "consistent"
included_path {
path = "/*"
}
excluded_path {
path = "/notes/*"
}
}
}
# The built-in Data Contributor role, scoped to the shop database.
resource "azurerm_cosmosdb_sql_role_assignment" "app" {
resource_group_name = azurerm_resource_group.cosmos.name
account_name = azurerm_cosmosdb_account.shop.name
role_definition_id = "${azurerm_cosmosdb_account.shop.id}/sqlRoleDefinitions/00000000-0000-0000-0000-000000000002"
principal_id = var.app_principal_id
scope = "${azurerm_cosmosdb_account.shop.id}/dbs/${azurerm_cosmosdb_sql_database.shop.name}"
}
output "endpoint" {
value = azurerm_cosmosdb_account.shop.endpoint
}
# pip install azure-cosmos azure-identity
# A safe insert, a point read, a query inside one partition and an update guarded by the item's ETag. Each call prints its RU charge.
import os
from azure.core import MatchConditions
from azure.cosmos import CosmosClient, exceptions
from azure.identity import DefaultAzureCredential
# For example https://cosmos-shop-1234.documents.azure.com:443/ . No key is used: the identity needs the Data Contributor role.
client = CosmosClient(os.environ["COSMOS_ENDPOINT"], credential=DefaultAzureCredential())
container = client.get_database_client("shop").get_container_client("orders")
def charge():
"""RU charge of the last request. This is the number to watch when you tune a query."""
return float(container.client_connection.last_response_headers.get("x-ms-request-charge", 0))
def place_order(order):
"""Creates the order. Returns False when an item with this id already exists in the partition, so a retried request is harmless."""
try:
container.create_item(order)
print("create_item: %.2f RU" % charge())
return True
except exceptions.CosmosResourceExistsError:
return False
def get_order(customer_id, order_id):
"""A point read needs the id and the partition key value. It is the cheapest read there is, about 1 RU for a 1 KB item."""
try:
item = container.read_item(item=order_id, partition_key=customer_id)
except exceptions.CosmosResourceNotFoundError:
return None
print("read_item: %.2f RU" % charge())
return item
def orders_of(customer_id):
"""A query that names the partition key stays inside one partition. Without partition_key it would be sent to all of them."""
items = list(container.query_items(
query="SELECT c.id, c.status, c.total FROM c WHERE c.customerId = @customer",
parameters=[{"name": "@customer", "value": customer_id}],
partition_key=customer_id,
))
print("query_items: %.2f RU for %d items" % (charge(), len(items)))
return items
def ship(customer_id, order_id):
"""Moves the order to SHIPPED unless somebody changed it after we read it (the ETag no longer matches)."""
item = get_order(customer_id, order_id)
if item is None or item["status"] != "PLACED":
return False
item["status"] = "SHIPPED"
try:
container.replace_item(item=item["id"], body=item, etag=item["_etag"], match_condition=MatchConditions.IfNotModified)
return True
except exceptions.CosmosAccessConditionFailedError:
return False # lost the race: read the item again and decide what to do
if __name__ == "__main__":
order = {"id": "o-0001", "customerId": "c-100", "status": "PLACED", "total": 2499}
print("created:", place_order(order))
print("created again:", place_order(order))
print(get_order("c-100", "o-0001"))
print(orders_of("c-100"))
print("shipped:", ship("c-100", "o-0001"))
// dotnet add package Microsoft.Azure.Cosmos
// dotnet add package Azure.Identity
// dotnet add package Newtonsoft.Json (recent SDK versions want this referenced explicitly, or the build stops with an error)
// Reads one order, runs the same query inside one partition and across all partitions, and prints what each cost in request units.
using System.Net;
using Azure.Identity;
using Microsoft.Azure.Cosmos;
string endpoint = Environment.GetEnvironmentVariable("COSMOS_ENDPOINT") ?? throw new InvalidOperationException("Set COSMOS_ENDPOINT first.");
using var client = new CosmosClient(endpoint, new DefaultAzureCredential());
Container orders = client.GetContainer("shop", "orders");
try
{
ItemResponse<Order> one = await orders.ReadItemAsync<Order>("o-0001", new PartitionKey("c-100"));
Console.WriteLine($"point read: {one.RequestCharge:F2} RU, status {one.Resource.status}");
}
catch (CosmosException ex) when (ex.StatusCode == HttpStatusCode.NotFound)
{
Console.WriteLine("o-0001 was not found. A point read needs the id and the partition key value, so check both.");
}
var query = new QueryDefinition("SELECT * FROM c WHERE c.status = @status").WithParameter("@status", "PLACED");
// Inside one partition: the cheap way.
double inPartition = await Charge(orders.GetItemQueryIterator<Order>(query, requestOptions: new QueryRequestOptions { PartitionKey = new PartitionKey("c-100") }));
// Across all partitions: every physical partition is asked, so the charge grows with the container.
double everywhere = await Charge(orders.GetItemQueryIterator<Order>(query));
Console.WriteLine($"query in one partition: {inPartition:F2} RU; query across partitions: {everywhere:F2} RU");
static async Task<double> Charge(FeedIterator<Order> iterator)
{
double total = 0;
while (iterator.HasMoreResults)
{
FeedResponse<Order> page = await iterator.ReadNextAsync();
total += page.RequestCharge;
}
return total;
}
public record Order(string id, string customerId, string status, double total);
Best videos to explore
Videos picked for this service. Each one is labelled with its source, opens on YouTube if you prefer, and loads only when you press play.
Interview questions
BasicWhat is Azure Cosmos DB?
It’s Microsoft’s fully managed, globally distributed NoSQL database. Its main API stores JSON items in containers, and there are APIs for MongoDB, Cassandra, Gremlin and Table too. You pick a partition key, pay for throughput in request units, and can replicate data to any Azure regions you add.
BasicWhat is a request unit?
A request unit (RU) is Cosmos DB’s measure of the work a request needs, a blend of CPU, memory and I/O. A point read of a 1 KB item costs about 1 RU, and writes, queries and larger items cost more. Throughput is bought as RU per second, and the response header x-ms-request-charge tells you what each call cost.
BasicWhat does the partition key do?
It decides which logical partition an item belongs to, and Cosmos DB spreads logical partitions over physical ones. A good key has many values and spreads reads and writes evenly. It can’t be changed after the container exists, so a poor choice means creating a new container and copying the data.
IntermediateProvisioned, autoscale or serverless: how do you choose?
Provisioned throughput fits steady, predictable load, because you pay a fixed rate for a fixed RU/s. Autoscale fits load that varies, since it scales between 10 percent and 100 percent of a maximum and bills the highest level reached each hour. Serverless has nothing to reserve and bills the RUs consumed, which suits development and low, spiky traffic, within its limits on storage and throughput.
IntermediateWhich consistency level would you use, and why?
Session is the default and the right choice for most applications: within a session a client reads its own writes and sees ordered data, at a low RU cost. Strong is for flows that can’t show stale data and can accept the latency across regions. Bounded staleness caps how far reads may lag, consistent prefix keeps order without a lag limit, and eventual gives the lowest cost and the weakest guarantees.
IntermediateHow do you secure an account without account keys?
Create the account with key-based access disabled and use Microsoft Entra ID. Assign the built-in Data Reader or Data Contributor role, or a custom role, to the application’s managed identity at account, database or container scope. A general Azure role such as Contributor controls the account but doesn’t grant data access. Add private endpoints and customer managed keys if your rules need them.
AdvancedHow do you choose a partition key for a multi-tenant application?
List the access patterns first. A tenant ID is a natural key if tenants are small and numerous, since every query includes it. If one tenant can be huge, a single value can reach the 20 GB logical partition limit or the 10,000 RU/s limit, so use a hierarchical key such as tenant and then user or date. Test with skewed, realistic traffic and watch normalised RU consumption per partition.
AdvancedA query is slow and uses thousands of RUs. How do you investigate?
Read the query metrics and the RU charge. Check whether the filter includes the partition key, since a cross-partition query asks every physical partition. Then check the indexing policy for the filtered and sorted paths, look for ORDER BY over several properties without a composite index, and see whether the query returns far more data than needed. Fix the query or the index, then compare the charge.
AdvancedHow would you design for multiple regions, failover and consistency?
Add the regions near your users, set preferred regions in the SDK and enable service-managed failover. Decide between a single write region, which keeps conflicts out, and multi-region writes, which cut write latency but need a conflict policy (last writer wins by default). Strong consistency across far-apart regions adds latency, so session consistency with the session token is common. Test a failover before you need it.
AdvancedYou are seeing 429 errors but total RU use is under the limit. What is going on?
Throughput is split over physical partitions, so one hot logical partition can use up its share while the account total looks low. Check NormalizedRUConsumption by partition key range. Fix the key or spread the hot key, raise throughput if the load is real, and reduce the RU cost of the hot operations. The SDK retries 429 responses, but retries don’t cure a sustained shortage.
Similar or alternative services on other clouds
| Capability | AWS | Azure | Google Cloud |
|---|---|---|---|
| Service | Amazon DynamoDB | Azure Cosmos DB (API for NoSQL) | Firestore |
| Data model | Tables of items, partition key and sort key | Containers of JSON items, partition key | Collections of documents, with subcollections |
| Capacity | On-demand, or provisioned with auto scaling | Request units: provisioned, autoscale or serverless | No capacity to set; billed per operation |
| Secondary indexes | Global and local indexes that you design | Every property indexed by default, with a policy to tune | Single-field indexes automatic, composite ones declared |
| Consistency | Eventual by default, strong per read | Five levels, session by default | Strongly consistent reads and queries |
| Multi-Region | Global tables | Multi-region replication and writes | Multi-region locations |
| Change feed | DynamoDB Streams, 24 hours | Change feed | Realtime listeners and event triggers |
| Recovery | Point-in-time recovery, 1 to 35 days | Continuous backup, 7 or 30 days | Point-in-time recovery, 7 days, and scheduled backups |
| How you are billed | Request units or capacity units, plus storage | Request units or throughput per hour, plus storage | Reads, writes and deletes, plus storage |
Typical partners are Azure Functions, which can react to the change feed, and Azure Event Grid for routing events onwards. Customer managed keys come from Azure Key Vault, and metrics and alerts live in Azure Monitor.
Did you find this article helpful?
Your answer helps us improve this page for the next reader.
Sources and further reading
CloudBrum wrote this page in its own words, using the provider’s public documentation listed below as the reference. Features, limits, names and prices change, so confirm anything that matters on the provider’s own pages before you decide.
- Welcome to Azure Cosmos DBMicrosoft
- Partitioning and horizontal scaling in Azure Cosmos DBMicrosoft
- Request Units in Azure Cosmos DBMicrosoft
- Consistency levels in Azure Cosmos DBMicrosoft
- Indexing policies in Azure Cosmos DBMicrosoft
- Configure role-based access control with Microsoft Entra IDMicrosoft
- Continuous backup with point-in-time restoreMicrosoft
- Azure Cosmos DB service quotasMicrosoft
- Azure Cosmos DB pricingMicrosoft
- Terraform azurerm: azurerm_cosmosdb_accountHashiCorp
