{"id":12670,"date":"2026-07-06T13:20:06","date_gmt":"2026-07-06T20:20:06","guid":{"rendered":"https:\/\/devblogs.microsoft.com\/cosmosdb\/?p=12670"},"modified":"2026-07-06T13:20:06","modified_gmt":"2026-07-06T20:20:06","slug":"see-our-new-azure-cosmos-db-design-patterns","status":"publish","type":"post","link":"https:\/\/devblogs.microsoft.com\/cosmosdb\/see-our-new-azure-cosmos-db-design-patterns\/","title":{"rendered":"See our new Azure Cosmos DB Design Patterns"},"content":{"rendered":"<p class=\"code-line\" dir=\"auto\" data-line=\"2\">Design patterns are where good data modeling lives or dies. In a NoSQL database like Azure Cosmos DB, the difference between a schema that scales to millions of operations per second and one that fights you at every turn usually comes down to a handful of well\u2011understood patterns: how you partition, how you version, how you fan out work, how you keep concurrent writers from stepping on each other.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"4\">That&#8217;s exactly what the\u00a0<a href=\"https:\/\/github.com\/Azure-Samples\/cosmos-db-design-patterns\" target=\"_blank\" rel=\"noopener\" data-href=\"https:\/\/github.com\/Azure-Samples\/cosmos-db-design-patterns\"><strong>Azure Cosmos DB Design Patterns<\/strong><\/a>\u00a0repo is for. It&#8217;s a growing, hands\u2011on collection of small, focused samples \u2014 each one isolates a single pattern, explains\u00a0<em>why<\/em>\u00a0it matters, and lets you\u00a0<strong>run it yourself<\/strong>\u00a0and watch it work.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"6\">We recently gave the repo a big update. Here&#8217;s what&#8217;s new.<\/p>\n<h2 id=\"the-core-idea-patterns-you-can-see-not-just-read-about\" class=\"code-line\" dir=\"auto\" data-line=\"8\">The core idea: patterns you can\u00a0<em>see<\/em>, not just read about<\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"10\">Most pattern catalogs are prose and diagrams. This repo takes a different stance:\u00a0<strong>every pattern ships as a runnable sample with an interactive web front end.<\/strong>\u00a0You don&#8217;t just read that a distributed lock uses fencing tokens \u2014 you start a few workers, watch them contend for the lock in real time, crash the holder, and see the lease auto\u2011release. The picture\u00a0<em>is<\/em>\u00a0the lesson.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"12\">Three principles guide the whole collection:<\/p>\n<ul class=\"code-line\" dir=\"auto\" data-line=\"14\">\n<li class=\"code-line\" dir=\"auto\" data-line=\"14\"><strong>Emulator\u2011first.<\/strong>\u00a0Every sample runs entirely on your machine against the <a href=\"https:\/\/learn.microsoft.com\/azure\/cosmos-db\/emulator-linux\" target=\"_blank\" rel=\"noopener\">Azure Cosmos DB Linux (vNext) emulator<\/a>. No Azure subscription, no account, no keys \u2014 just\u00a0<code>docker compose up -d<\/code>\u00a0and\u00a0<code>dotnet run<\/code>. Zero setup is the default path.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"15\"><strong>Interactive web UX for every pattern.<\/strong>\u00a0A small Blazor front end turns each abstract pattern into something you can click, break, and reason about \u2014 with &#8220;why it matters&#8221; talking points built right into the page.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"16\"><strong>Secure and optional cloud.<\/strong>\u00a0When you\u00a0<em>do<\/em>\u00a0want to see it in Azure, each sample includes a one\u2011command Azure Developer CLI (<code>azd<\/code>) template that provisions a\u00a0<strong>keyless<\/strong>\u00a0(Microsoft Entra ID + managed identity) deployment \u2014 no secrets stored anywhere.<\/li>\n<\/ul>\n<h2 id=\"five-brandnew-patterns\" class=\"code-line\" dir=\"auto\" data-line=\"18\">Five brand\u2011new patterns<\/h2>\n<h3 id=\"1-vector-search\" class=\"code-line\" dir=\"auto\" data-line=\"20\">1. Vector Search<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"22\">Semantic search over your operational data using <a href=\"https:\/\/learn.microsoft.com\/azure\/cosmos-db\/vector-search\" target=\"_blank\" rel=\"noopener\">Azure Cosmos DB&#8217;s\u00a0<strong>built\u2011in vector indexing<\/strong><\/a>\u00a0and the\u00a0<code>VectorDistance()<\/code>\u00a0function \u2014 the storage\u2011and\u2011retrieval foundation of RAG. What makes this sample special: it embeds text with a\u00a0<strong>small local model<\/strong>, so there&#8217;s no API key and no external service. That quietly solves a real pain point \u2014 you can build and CI\/CD an app that uses embeddings\u00a0<strong>without pre\u2011deploying a foundation model or baking keys into GitHub secrets<\/strong>.<\/p>\n<h3 id=\"2-loopsafe-change-feed\" class=\"code-line\" dir=\"auto\" data-line=\"24\">2. Loop\u2011Safe Change Feed<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"26\">A classic trap: you use the change feed to\u00a0<em>derive<\/em>\u00a0a value and write it back onto the\u00a0<strong>same<\/strong>\u00a0document \u2014 and your write re\u2011triggers the feed, which writes again\u2026 forever. This sample shows the standard fix: store a\u00a0<strong>hash of the source<\/strong>\u00a0and skip any change whose hash is unchanged (the echo of your own write). One real edit produces exactly\u00a0<strong>one enrichment and one skipped echo<\/strong>\u00a0\u2014 the loop is bounded instead of runaway.<\/p>\n<p dir=\"auto\" data-line=\"26\"><a href=\"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2026\/07\/loop-safe-change-feed-web.png\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-12672\" src=\"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2026\/07\/loop-safe-change-feed-web.png\" alt=\"The Loop\u2011Safe Change Feed web front end: documents with generated identicons, an enrichment\u2011writes vs. skipped\u2011echoes counter staying in lock\u2011step, and an ENRICHED\/SKIPPED change\u2011feed timeline.\" width=\"1280\" height=\"818\" srcset=\"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2026\/07\/loop-safe-change-feed-web.png 1280w, https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2026\/07\/loop-safe-change-feed-web-300x192.png 300w, https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2026\/07\/loop-safe-change-feed-web-1024x654.png 1024w, https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2026\/07\/loop-safe-change-feed-web-768x491.png 768w\" sizes=\"(max-width: 1280px) 100vw, 1280px\" \/><\/a><\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"30\"><em>Each document gets an identicon derived from its text. The\u00a0<strong>enrichment writes<\/strong>\u00a0and\u00a0<strong>skipped echoes<\/strong>\u00a0counters climb together \u2014 one of each per edit \u2014 which is the loop\u2011safety guarantee made visible.<\/em><\/p>\n<h3 id=\"3-hierarchical-partition-key\" class=\"code-line\" dir=\"auto\" data-line=\"32\">3. Hierarchical Partition Key<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"34\">When a single partition key isn&#8217;t enough,<a href=\"https:\/\/learn.microsoft.com\/azure\/cosmos-db\/hierarchical-partition-keys\" target=\"_blank\" rel=\"noopener\">\u00a0<strong>hierarchical (sub)partitioning<\/strong><\/a>\u00a0lets you distribute data across multiple key levels while keeping related items co\u2011located. The sample models a realistic multi\u2011tenant shape and shows the cost and performance impact of getting your partition strategy right.<\/p>\n<h3 id=\"4-transactional-outbox\" class=\"code-line\" dir=\"auto\" data-line=\"36\">4. Transactional Outbox<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"38\">Placing an order should both\u00a0<strong>change state<\/strong>\u00a0and\u00a0<strong>publish an event<\/strong>\u00a0other systems consume \u2014 reliably. Doing those as two separate writes is a\u00a0<em>dual\u2011write<\/em>, and a crash in between loses the event. This sample writes the order\u00a0<strong>and<\/strong>\u00a0the event in a single atomic\u00a0<code>TransactionalBatch<\/code>, then relays the event with the change feed \u2014 so it can never be lost, even if the app dies the instant after commit. There&#8217;s a crash\u2011toggle playground that lets you watch the naive version lose events while the outbox never does.<\/p>\n<p dir=\"auto\" data-line=\"38\"><a href=\"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2026\/07\/transactional-outbox-web.png\"><img decoding=\"async\" class=\"aligncenter size-full wp-image-12673\" src=\"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2026\/07\/transactional-outbox-web.png\" alt=\"transactional outbox web image\" width=\"1200\" height=\"1720\" srcset=\"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2026\/07\/transactional-outbox-web.png 1200w, https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2026\/07\/transactional-outbox-web-209x300.png 209w, https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2026\/07\/transactional-outbox-web-714x1024.png 714w, https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2026\/07\/transactional-outbox-web-768x1101.png 768w, https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2026\/07\/transactional-outbox-web-1072x1536.png 1072w\" sizes=\"(max-width: 1200px) 100vw, 1200px\" \/><\/a><\/p>\n<h3 id=\"5-patch-api-partial-document-update\" class=\"code-line\" dir=\"auto\" data-line=\"40\">5. Patch API (Partial Document Update)<\/h3>\n<p class=\"code-line\" dir=\"auto\" data-line=\"42\">Updating one field usually means a read\u2011modify\u2011write: read the whole document, change a field, write it all back. The\u00a0<a href=\"https:\/\/learn.microsoft.com\/azure\/cosmos-db\/partial-document-update\" target=\"_blank\" rel=\"noopener\"><strong>Patch API<\/strong><\/a>\u00a0sends only the operation instead \u2014 cheaper, lower latency, and no lost updates when different services update different fields. The sample makes the trade\u2011offs concrete with a three\u2011way concurrency race, measured on the emulator:<\/p>\n<table class=\"code-line\" dir=\"auto\" data-line=\"44\">\n<thead class=\"code-line\" dir=\"auto\" data-line=\"44\">\n<tr class=\"code-line\" dir=\"auto\" data-line=\"44\">\n<th>Approach<\/th>\n<th>Result<\/th>\n<th>Conflicts<\/th>\n<th>RU<\/th>\n<\/tr>\n<\/thead>\n<tbody class=\"code-line\" dir=\"auto\" data-line=\"46\">\n<tr class=\"code-line\" dir=\"auto\" data-line=\"46\">\n<td>Read\u2011modify\u2011write, no ETag<\/td>\n<td>\u274c an update is\u00a0<strong>lost<\/strong><\/td>\n<td>0<\/td>\n<td>4<\/td>\n<\/tr>\n<tr class=\"code-line\" dir=\"auto\" data-line=\"47\">\n<td>Read\u2011modify\u2011write\u00a0<strong>+ ETag<\/strong><\/td>\n<td>\u2705 correct, after re\u2011read + retry<\/td>\n<td>1<\/td>\n<td>6<\/td>\n<\/tr>\n<tr class=\"code-line\" dir=\"auto\" data-line=\"48\">\n<td><strong>Patch<\/strong><\/td>\n<td>\u2705 correct<\/td>\n<td>0<\/td>\n<td><strong>2<\/strong><\/td>\n<\/tr>\n<\/tbody>\n<\/table>\n<p class=\"code-line\" dir=\"auto\" data-line=\"50\">The honest punchline: an ETag makes read\u2011modify\u2011write\u00a0<em>correct<\/em>, but because it guards the whole document, two services touching\u00a0<em>different<\/em>\u00a0fields still collide with a needless\u00a0<code>412<\/code>\u00a0and pay to retry. Patch just\u2026 doesn&#8217;t.<\/p>\n<h2 id=\"a-pattern-in-motion-the-reworked-distributed-lock\" class=\"code-line\" dir=\"auto\" data-line=\"52\">A pattern in motion: the reworked Distributed Lock<\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"54\">Distributed Lock isn&#8217;t new to the repo, but it got a full rework and a live web playground this cycle \u2014 and it&#8217;s the best single illustration of the &#8220;see it work&#8221; philosophy. Every acquire, renewal, and release you see is a\u00a0<strong>real operation against Azure Cosmos DB<\/strong>.<\/p>\n<p dir=\"auto\" data-line=\"54\"><a href=\"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2026\/07\/distributed-lock-web.png\"><img decoding=\"async\" class=\"aligncenter wp-image-12671 size-full\" src=\"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2026\/07\/distributed-lock-web.png\" alt=\"The Distributed Lock web front end: three workers competing for a lock, with Worker\u2011B holding it (fencing token 11131) while Workers A and C are locked out, a protected resource showing 17 accepted \/ 0 rejected writes, and a live event timeline.\" width=\"1280\" height=\"1259\" srcset=\"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2026\/07\/distributed-lock-web.png 1280w, https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2026\/07\/distributed-lock-web-300x295.png 300w, https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2026\/07\/distributed-lock-web-1024x1007.png 1024w, https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2026\/07\/distributed-lock-web-768x755.png 768w, https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2026\/07\/distributed-lock-web-24x24.png 24w, https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-content\/uploads\/sites\/52\/2026\/07\/distributed-lock-web-48x48.png 48w\" sizes=\"(max-width: 1280px) 100vw, 1280px\" \/><\/a><\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"58\"><em>Only one worker holds the lock at a time (mutual exclusion). The holder carries a\u00a0<strong>fencing token<\/strong>; the protected resource accepts only the current holder&#8217;s token, so a stale writer&#8217;s updates are rejected. Crash the holder and the lease auto\u2011releases via TTL \u2014 no deadlock.<\/em><\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"60\">Drag a worker&#8217;s\u00a0<em>Work<\/em>\u00a0longer than the lock TTL and watch auto\u2011renew keep the lease alive. Turn auto\u2011renew off and watch the lease expire mid\u2011work, another worker take over, and the stale holder&#8217;s writes get rejected by the fencing token. It&#8217;s a whole distributed\u2011systems lecture you can run in a browser tab.<\/p>\n<h2 id=\"under-the-hood-quality-that-makes-the-samples-trustworthy\" class=\"code-line\" dir=\"auto\" data-line=\"62\">Under the hood: quality that makes the samples trustworthy<\/h2>\n<p class=\"code-line\" dir=\"auto\" data-line=\"64\">Alongside the new patterns, the repo got a foundation upgrade:<\/p>\n<ul class=\"code-line\" dir=\"auto\" data-line=\"66\">\n<li class=\"code-line\" dir=\"auto\" data-line=\"66\"><strong>.NET 10<\/strong>\u00a0across every sample.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"67\"><strong>Emulator\u2011backed integration tests in CI<\/strong>\u00a0\u2014 the test suite runs against the Cosmos DB Linux emulator on every pull request, with\u00a0<strong>no secrets<\/strong>, so the patterns are verified to actually work.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"68\"><strong>Keyless\u00a0<code>azd<\/code>\u00a0deployments<\/strong>\u00a0for every sample \u2014 managed identity, local key auth disabled, nothing sensitive stored.<\/li>\n<li class=\"code-line\" dir=\"auto\" data-line=\"69\"><strong>Unified, streamlined docs<\/strong>\u00a0\u2014 every sample&#8217;s README now follows the same shape (get the code \u2192 configure \u2192 run locally \u2192 optionally deploy), linking back to a shared setup guide instead of repeating stale portal instructions.<\/li>\n<\/ul>\n<h2 id=\"try-it-in-five-minutes\" class=\"code-line\" dir=\"auto\" data-line=\"71\">Try it in five minutes<\/h2>\n<pre><code class=\"code-line language-bash\" dir=\"auto\" data-line=\"73\">git <span class=\"hljs-built_in\">clone<\/span> https:\/\/github.com\/Azure-Samples\/cosmos-db-design-patterns.git\r\n<span class=\"hljs-built_in\">cd<\/span> cosmos-db-design-patterns\r\ndocker compose up -d          <span class=\"hljs-comment\"># start the local emulator<\/span>\r\n<span class=\"hljs-built_in\">cd<\/span> loop-safe-change-feed\/source\/Website\r\ndotnet run                    <span class=\"hljs-comment\"># open the URL it prints<\/span>\r\n<\/code><\/pre>\n<p class=\"code-line\" dir=\"auto\" data-line=\"81\">Pick any pattern folder, run its web front end, and start clicking. Whether you&#8217;re choosing a partition strategy, wiring up reliable eventing, or reaching for vector search, there&#8217;s now a small, honest, runnable example waiting to show you how it behaves \u2014\u00a0<strong>before<\/strong>\u00a0you build it for real.<\/p>\n<p class=\"code-line\" dir=\"auto\" data-line=\"83\">\ud83d\udc49\u00a0<strong><a href=\"https:\/\/github.com\/Azure-Samples\/cosmos-db-design-patterns\" target=\"_blank\" rel=\"noopener\" data-href=\"https:\/\/github.com\/Azure-Samples\/cosmos-db-design-patterns\">Explore the Azure Cosmos DB Design Patterns repo<\/a><\/strong> and let us know which pattern you&#8217;d like to see next by adding ideas to our GitHub Issues.<\/p>\n","protected":false},"excerpt":{"rendered":"<p>Design patterns are where good data modeling lives or dies. In a NoSQL database like Azure Cosmos DB, the difference between a schema that scales to millions of operations per second and one that fights you at every turn usually comes down to a handful of well\u2011understood patterns: how you partition, how you version, how [&hellip;]<\/p>\n","protected":false},"author":8297,"featured_media":12677,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"_acf_changed":false,"footnotes":""},"categories":[12,1828,19],"tags":[],"class_list":["post-12670","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-announcements","category-data-modeling","category-tips-and-tricks"],"acf":[],"blog_post_summary":"<p>Design patterns are where good data modeling lives or dies. In a NoSQL database like Azure Cosmos DB, the difference between a schema that scales to millions of operations per second and one that fights you at every turn usually comes down to a handful of well\u2011understood patterns: how you partition, how you version, how [&hellip;]<\/p>\n","_links":{"self":[{"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/posts\/12670","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/users\/8297"}],"replies":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/comments?post=12670"}],"version-history":[{"count":2,"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/posts\/12670\/revisions"}],"predecessor-version":[{"id":12678,"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/posts\/12670\/revisions\/12678"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/media\/12677"}],"wp:attachment":[{"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/media?parent=12670"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/categories?post=12670"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/devblogs.microsoft.com\/cosmosdb\/wp-json\/wp\/v2\/tags?post=12670"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}