How to build a CRUD API on Azure Cosmos DB
Model documents and run CRUD operations on Azure Cosmos DB for NoSQL from .NET. Covers partition key choice, throughput, and SQL queries.
Azure Cosmos DB is a globally distributed, multi-model database. The most common API, Cosmos DB for NoSQL, stores JSON documents and queries them with a SQL-like dialect. Throughput is measured in Request Units (RUs). Choosing a good partition key is the single most important design decision for cost and scale.
Prerequisites
- An Azure subscription and the Azure CLI.
- .NET 8 and the
Microsoft.Azure.CosmosNuGet package.
Steps
1. Create an account
az cosmosdb create --name cosmos-$RANDOM --resource-group rg-app --kind GlobalDocumentDB
2. Pick a partition key
Choose a key with high cardinality and even access, for example /customerId. A poor key creates hot partitions that throttle.
3. Create the container
az cosmosdb sql database create --account-name <acct> --resource-group rg-app --name shop
az cosmosdb sql container create --account-name <acct> --resource-group rg-app \
--database-name shop --name orders --partition-key-path /customerId --throughput 400
4. Upsert documents
var client = new CosmosClient(endpoint, key);
var container = client.GetContainer("shop", "orders");
var order = new { id = "1", customerId = "c-123", total = 42 };
await container.UpsertItemAsync(order, new PartitionKey("c-123"));
UpsertItemAsync creates or replaces in one call.
5. Read and delete
var read = await container.ReadItemAsync<Order>("1", new PartitionKey("c-123"));
await container.DeleteItemAsync<Order>("1", new PartitionKey("c-123"));
Always pass the partition key, it makes point operations efficient.
6. Query with SQL
var query = new QueryDefinition("SELECT * FROM c WHERE c.total > @min").WithParameter("@min", 10);
var iterator = container.GetItemQueryIterator<Order>(query);
Queries scoped to a single partition cost fewer RUs than cross-partition queries.
Verification
Use the Data Explorer in the Azure Portal to confirm documents exist with the expected partition key. Inspect the RequestCharge property on responses to track RU consumption and catch expensive queries early.
Next Steps
Switch to autoscale throughput, add a second region for global reads, and tune indexing policy to exclude paths you never filter on.