<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Abhishek Gupta</title>
    <description>The latest articles on DEV Community by Abhishek Gupta (@abhirockzz).</description>
    <link>https://dev.to/abhirockzz</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F182847%2F60bbac9f-e6af-4220-bf17-dae44fffa2de.jpg</url>
      <title>DEV Community: Abhishek Gupta</title>
      <link>https://dev.to/abhirockzz</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/abhirockzz"/>
    <language>en</language>
    <item>
      <title>Need a different partition key in Azure Cosmos DB? Pick the right approach</title>
      <dc:creator>Abhishek Gupta</dc:creator>
      <pubDate>Mon, 20 Jul 2026 17:10:24 +0000</pubDate>
      <link>https://dev.to/abhirockzz/need-a-different-partition-key-in-azure-cosmos-db-pick-the-right-approach-gji</link>
      <guid>https://dev.to/abhirockzz/need-a-different-partition-key-in-azure-cosmos-db-pick-the-right-approach-gji</guid>
      <description>&lt;p&gt;Once you create a container, its &lt;a href="https://learn.microsoft.com/azure/cosmos-db/partitioning" rel="noopener noreferrer"&gt;partition key&lt;/a&gt; is fixed at creation, and you can't change it in place. However, if your original key starts causing problems like &lt;a href="https://learn.microsoft.com/azure/cosmos-db/how-to-query-container#avoid-cross-partition-queries" rel="noopener noreferrer"&gt;cross-partition queries&lt;/a&gt; or &lt;a href="https://learn.microsoft.com/azure/cosmos-db/troubleshoot-request-rate-too-large#how-to-identify-the-hot-partition" rel="noopener noreferrer"&gt;hot partitions&lt;/a&gt;, you need to consider your options for changing it. This post explains the mechanics of changing a partition key, and the tradeoffs between the options.&lt;/p&gt;

&lt;p&gt;First, think about the &lt;strong&gt;intent&lt;/strong&gt; of your change:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Re-partition the data.&lt;/strong&gt; You want your items (and future &lt;em&gt;writes&lt;/em&gt;) to live under a different key. This means moving to a new container and there are three ways, from least to most effort: &lt;a href="https://learn.microsoft.com/azure/cosmos-db/change-partition-key" rel="noopener noreferrer"&gt;Change partition key&lt;/a&gt; feature, &lt;a href="https://learn.microsoft.com/azure/cosmos-db/container-copy" rel="noopener noreferrer"&gt;container copy jobs&lt;/a&gt;, or a do-it-yourself migration.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Query by a different key without moving.&lt;/strong&gt; Your writes are fine where they are, and you only have &lt;em&gt;read&lt;/em&gt; patterns that fan out across partitions. A Global Secondary Index adds a separate, read-only, automatically-synchronized container with a different partition key and its own data model, a projection of your items (all properties, or just a subset). The source container stays unchanged.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Note that every "change the partition key" option is actually a &lt;strong&gt;move&lt;/strong&gt;: get your data into a &lt;em&gt;new&lt;/em&gt; container that has the new key, then point your app at it. The exception is a &lt;a href="https://learn.microsoft.com/azure/cosmos-db/global-secondary-indexes" rel="noopener noreferrer"&gt;Global Secondary Index&lt;/a&gt;, which adds a different key for read patterns while the source container stays unchanged.&lt;/p&gt;

&lt;p&gt;Let's walk through each path and its tradeoffs.&lt;/p&gt;

&lt;h2&gt;
  
  
  Re-partition the data
&lt;/h2&gt;

&lt;p&gt;The three options below all land your data in a &lt;em&gt;new&lt;/em&gt; container with the new key. But, they differ in how much Azure Cosmos DB does for you, whether you can keep writing to the source while the copy runs, and how much control you have over the cutover.&lt;/p&gt;

&lt;h3&gt;
  
  
  Option 1: the portal Change partition key feature (least effort)
&lt;/h3&gt;

&lt;p&gt;The portal feature is the managed path. In the Azure portal, open &lt;strong&gt;Data Explorer&lt;/strong&gt;, pick your container, go to &lt;strong&gt;Scale &amp;amp; Settings → Partition Keys&lt;/strong&gt;, and select &lt;strong&gt;Change&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;The portal creates or selects a destination container in the same database, then copies your data into it using &lt;a href="https://learn.microsoft.com/azure/cosmos-db/container-copy" rel="noopener noreferrer"&gt;container copy jobs&lt;/a&gt; (Option 2 covers those, since they're the same engine). If you let the portal create the destination container for you, all configurations except the partition key and unique keys are replicated to the destination, so you only restate those two. You can run the copy &lt;strong&gt;online&lt;/strong&gt; or &lt;strong&gt;offline&lt;/strong&gt; (the next section explains what that means). In online mode you finish the job by selecting &lt;strong&gt;Complete&lt;/strong&gt;, and once the copy is done you start using the new container with the new key and optionally delete the old one.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Read more in the Change partition key &lt;a href="https://learn.microsoft.com/azure/cosmos-db/change-partition-key#limitations" rel="noopener noreferrer"&gt;limitations&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Option 2: container copy jobs directly (same engine, scriptable)
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://learn.microsoft.com/azure/cosmos-db/container-copy" rel="noopener noreferrer"&gt;Container copy jobs&lt;/a&gt; are the engine behind the portal capability. You can also create and manage them yourself with &lt;a href="https://learn.microsoft.com/azure/cosmos-db/how-to-container-copy" rel="noopener noreferrer"&gt;Azure CLI&lt;/a&gt; (via the &lt;code&gt;cosmosdb-preview&lt;/code&gt; extension), which is what you want for scripting, automation, or finer control. The workflow is: create the target container with the partition key (and throughput, unique keys, etc.) you want, create the copy job, monitor it, and cut over. When the source and destination are in &lt;em&gt;different&lt;/em&gt; accounts, you first give the destination account's identity read access to the source container. Same-account copies don't need this step.&lt;/p&gt;

&lt;p&gt;Container copy has two modes: online, where writes continue during the copy, and offline, where you stop writes before the job starts.&lt;/p&gt;

&lt;p&gt;Online mode keeps writes flowing during the copy and ends with a short Complete-then-cutover, but every source write is charged double RUs while online copy is enabled, and it needs continuous backup, &lt;a href="https://learn.microsoft.com/azure/cosmos-db/change-feed-modes?tabs=latest-version#all-versions-and-deletes-change-feed-mode" rel="noopener noreferrer"&gt;all-versions-and-deletes change feed&lt;/a&gt;, and the account-level capability switched on first. Offline skips those prerequisites at the cost of a write freeze on the source until you cut over. The &lt;a href="https://learn.microsoft.com/azure/cosmos-db/container-copy" rel="noopener noreferrer"&gt;Container copy jobs&lt;/a&gt; documentation walks through the prerequisites and cutover for both modes.&lt;/p&gt;

&lt;p&gt;Both modes run on a best-effort basis (there's no guaranteed completion time), and jobs run one at a time in the write region. Two things are worth planning for: a copy doesn't carry TTL across, so an item that hasn't expired restarts its countdown in the destination, and you'll want the target provisioned at roughly twice the source throughput to keep up.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Before you cut over:&lt;/strong&gt; A new container is also your one window to turn on features that can only be set at creation, the clearest being hierarchical partition keys, so weigh them now if they fit your workload. And since you're re-keying everything, confirm the new partition key value plus id is unique across the destination, or two formerly distinct items can collide.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Option 3: roll your own migration (most control, most work)
&lt;/h3&gt;

&lt;p&gt;If you need transforms during the move, your container exceeds the container-copy limits, or you just want full ownership of the process, create the new container yourself and move the data with your own pipeline. The &lt;a href="https://learn.microsoft.com/azure/cosmos-db/migrate" rel="noopener noreferrer"&gt;large-scale migration guidance&lt;/a&gt; covers the building blocks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Bulk ingestion&lt;/strong&gt; to load the new container fast: the .NET v3 SDK has it built in, and the &lt;a href="https://learn.microsoft.com/azure/cosmos-db/bulk-executor-overview" rel="noopener noreferrer"&gt;bulk executor library&lt;/a&gt; covers apps still on .NET SDK 2.x.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Azure Data Factory&lt;/strong&gt; for smaller datasets (configure source and sink, no code), or the &lt;strong&gt;Spark connector&lt;/strong&gt; if you already work in Spark.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://learn.microsoft.com/azure/cosmos-db/change-feed" rel="noopener noreferrer"&gt;Change feed&lt;/a&gt;&lt;/strong&gt; to catch writes that land on the source after your bulk load and replay them into the new container until you cut over. Its default &lt;a href="https://learn.microsoft.com/azure/cosmos-db/change-feed-modes" rel="noopener noreferrer"&gt;latest-version mode&lt;/a&gt; skips deletes and TTL expirations, so use all-versions-and-deletes (which needs continuous backup) to handle delete operations.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Pre-create the destination with enough RU/s and turn off indexing during the load to hold down write cost. You own incremental sync, error handling, cutover, and any reshaping along the way.&lt;/p&gt;

&lt;h2&gt;
  
  
  Query by a different key, without moving (global secondary index)
&lt;/h2&gt;

&lt;p&gt;If your only pain is cross-partition queries (reads that fan out because your filter property isn't the partition key), you may not need to move at all. For that case, use &lt;a href="https://learn.microsoft.com/azure/cosmos-db/global-secondary-indexes" rel="noopener noreferrer"&gt;global secondary indexes&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;A global secondary index (GSI) is a separate, read-only container keyed by a &lt;em&gt;different&lt;/em&gt; partition key, with its own data model. That model is a projection query over your items (&lt;code&gt;SELECT *&lt;/code&gt; for all properties, or just the subset you query), and it stays automatically synchronized with the source container. You keep writing to your existing container with its existing key, and queries whose filter matches the GSI's partition key (the specific patterns you built the GSI for) can become single-partition queries against the GSI instead of cross-partition queries on the source. A GSI helps the patterns it's keyed for, not every cross-partition query.&lt;/p&gt;

&lt;p&gt;GSIs fit when changing your existing partition key would be disruptive, and you have multiple query patterns that no single key can satisfy. A GSI needs continuous backups on the account, stays eventually consistent regardless of your consistency level, and runs on autoscale with its own storage and RU costs. Once one exists, replace and delete on the source cost 50–100% more RU (creates aren't affected), and &lt;a href="https://learn.microsoft.com/azure/cosmos-db/global-secondary-indexes" rel="noopener noreferrer"&gt;global secondary indexes&lt;/a&gt; cover the rest.&lt;/p&gt;

&lt;p&gt;A GSI fixes reads. It doesn't change where your &lt;em&gt;writes&lt;/em&gt; land, so it won't relieve a write-side hot partition on the source. If your problem is write distribution, or you need a different primary key for the data, you're back to the data re-partitioning option above and you have to move.&lt;/p&gt;

&lt;h2&gt;
  
  
  To wrap up
&lt;/h2&gt;

&lt;p&gt;If your writes need a different key, you end up moving the data, and the only question left is how much of the copy you hand to Azure Cosmos DB. If only your reads fan out, a GSI fixes that without changing where your writes land. The table below puts all four side by side.&lt;/p&gt;

&lt;h3&gt;
  
  
  Decision table
&lt;/h3&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Option&lt;/th&gt;
&lt;th&gt;Keep writing to the source during the move?&lt;/th&gt;
&lt;th&gt;Effort&lt;/th&gt;
&lt;th&gt;Use it when&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Portal "Change partition key"&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes (online mode) or no (offline)&lt;/td&gt;
&lt;td&gt;Lowest&lt;/td&gt;
&lt;td&gt;You want point-and-click, container &amp;lt; 1,000,000 RU/s, &amp;lt; 4 TB, supported region&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Container copy jobs (CLI)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes (online) or no (offline)&lt;/td&gt;
&lt;td&gt;Low–medium&lt;/td&gt;
&lt;td&gt;You want the managed engine but scripted, with explicit online/offline control&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Roll your own (bulk / ADF / Spark + change feed)&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Yes, if you build incremental sync yourself&lt;/td&gt;
&lt;td&gt;Highest&lt;/td&gt;
&lt;td&gt;You need transforms, are above the copy limits, or want full control of cutover&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Global secondary index&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;N/A, source stays as-is, GSI auto-synced&lt;/td&gt;
&lt;td&gt;Medium&lt;/td&gt;
&lt;td&gt;The pain is cross-partition &lt;em&gt;reads&lt;/em&gt;, not write hot partitions, and you can keep the source key&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;h2&gt;
  
  
  Learn more
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/azure/cosmos-db/partitioning" rel="noopener noreferrer"&gt;Partitioning in Azure Cosmos DB&lt;/a&gt;, &lt;a href="https://learn.microsoft.com/azure/cosmos-db/change-partition-key" rel="noopener noreferrer"&gt;Change the partition key (portal feature)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/azure/cosmos-db/container-copy" rel="noopener noreferrer"&gt;Container copy jobs&lt;/a&gt;, &lt;a href="https://learn.microsoft.com/azure/cosmos-db/how-to-container-copy" rel="noopener noreferrer"&gt;Create and manage container copy jobs (CLI)&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/azure/cosmos-db/global-secondary-indexes" rel="noopener noreferrer"&gt;Global secondary indexes&lt;/a&gt;, &lt;a href="https://learn.microsoft.com/azure/cosmos-db/hierarchical-partition-keys" rel="noopener noreferrer"&gt;Hierarchical partition keys&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/azure/cosmos-db/migrate" rel="noopener noreferrer"&gt;Migrate large amounts of data&lt;/a&gt;, &lt;a href="https://learn.microsoft.com/azure/cosmos-db/bulk-executor-overview" rel="noopener noreferrer"&gt;Bulk executor library overview&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;&lt;a href="https://learn.microsoft.com/azure/cosmos-db/change-feed-modes" rel="noopener noreferrer"&gt;Change feed modes&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>database</category>
      <category>azure</category>
      <category>nosql</category>
    </item>
    <item>
      <title>AI agents, meet the Azure Cosmos DB vNext emulator</title>
      <dc:creator>Abhishek Gupta</dc:creator>
      <pubDate>Mon, 20 Jul 2026 17:08:31 +0000</pubDate>
      <link>https://dev.to/abhirockzz/ai-agents-meet-the-azure-cosmos-db-vnext-emulator-3b7</link>
      <guid>https://dev.to/abhirockzz/ai-agents-meet-the-azure-cosmos-db-vnext-emulator-3b7</guid>
      <description>&lt;p&gt;If you use the Azure Cosmos DB vNext emulator, you probably know the local development loop: start the emulator, connect to it, create some resources, load test data, run queries, and inspect the results. Each step is straightforward, but together they add setup work before you can test the application you are actually building.&lt;/p&gt;

&lt;h2&gt;
  
  
  How agents work with the emulator
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff337uuoxiqangzqvt9yy.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Ff337uuoxiqangzqvt9yy.png" alt="Five-step workflow from developer intent through the coding agent, Agent Skill, Cosmos DB Shell, and the vNext emulator" width="800" height="400"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The emulator &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/emulator-linux#use-azure-cosmos-db-shell-with-the-emulator" rel="noopener noreferrer"&gt;includes Cosmos DB Shell&lt;/a&gt;, an open-source CLI for working with databases, containers, and items. It runs inside the emulator container and handles the local endpoint and well-known key, giving developers a direct, scriptable way to work with the emulator.&lt;/p&gt;

&lt;p&gt;CLIs are well suited to agent workflows because they expose operations as explicit commands and return results the agent can inspect. An agent can discover commands through built-in help, run them non-interactively, respond to errors, and use the output to choose its next action. These characteristics make the CLI a practical &lt;a href="https://x.com/ericzakariasson/status/2036762680401223946" rel="noopener noreferrer"&gt;interface for agents&lt;/a&gt;. Cosmos DB Shell brings that model to the local emulator.&lt;/p&gt;

&lt;p&gt;For example, an agent can run Cosmos DB Shell non-interactively inside the emulator container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &amp;lt;emulator-container&amp;gt; cosmoshell.sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="s1"&gt;'&amp;lt;command&amp;gt;'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It gives AI coding agents, such as &lt;a href="https://docs.github.com/en/copilot/how-tos/copilot-cli" rel="noopener noreferrer"&gt;GitHub Copilot CLI&lt;/a&gt;, Codex, and Claude Code, a straightforward way to work with the emulator. The developer describes the required outcome instead of translating the task into a sequence of shell commands. Command access is only the starting point. The agent still needs an operating procedure for finding the emulator, choosing appropriate commands, respecting safety boundaries, and verifying its work.&lt;/p&gt;

&lt;p&gt;An &lt;a href="https://agentskills.io/home" rel="noopener noreferrer"&gt;Agent Skill&lt;/a&gt; fills that gap by packaging task-specific guidance for reuse across requests and sessions. For the local emulator, the &lt;a href="https://github.com/abhirockzz/cosmosdb-vnext-emulator-skill" rel="noopener noreferrer"&gt;&lt;code&gt;cosmosdb-emulator-vnext&lt;/code&gt;&lt;/a&gt; skill helps the agent inspect resources, create databases and containers, load test data, and run queries through Cosmos DB Shell.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Explore the skill on GitHub:&lt;/strong&gt; &lt;a href="https://github.com/abhirockzz/cosmosdb-vnext-emulator-skill" rel="noopener noreferrer"&gt;cosmosdb-vnext-emulator-skill&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  From prompt to local test data
&lt;/h2&gt;

&lt;p&gt;Consider a developer building a multi-tenant order-processing application. The integration tests need data across multiple tenants and different stages of the order lifecycle. Creating and maintaining that data by hand can quickly become tedious.&lt;/p&gt;

&lt;p&gt;Instead, the developer could give a coding agent this prompt:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I’m building a multi-tenant order-processing app and need realistic data
for integration testing. Set up my local Cosmos DB emulator with synthetic
orders covering two tenants and a mix of new, shipped, and cancelled orders.
Show me the data when it’s ready.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;I tested this prompt with GitHub Copilot CLI while the local emulator was already running. The agent located the emulator, used the bundled Cosmos DB Shell, and created &lt;code&gt;OrdersDB&lt;/code&gt; with an &lt;code&gt;Orders&lt;/code&gt; container partitioned by &lt;code&gt;/tenantId&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;It then generated a balanced set of synthetic orders for both tenants. Each order included customer details, nested line items, timestamps, shipping information, and totals. It also added status-specific fields, such as tracking information for shipped orders and cancellation reasons for cancelled ones.&lt;/p&gt;

&lt;p&gt;The setup summary showed what the agent created:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Database: OrdersDB
Container: Orders
Partition key: /tenantId
Orders created: 12
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;To verify the data, the agent queried the container. Six of the 12 orders are shown below:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Order&lt;/th&gt;
&lt;th&gt;Tenant&lt;/th&gt;
&lt;th&gt;Customer&lt;/th&gt;
&lt;th&gt;Status&lt;/th&gt;
&lt;th&gt;Total&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;ord-a001&lt;/td&gt;
&lt;td&gt;tenant-alpha&lt;/td&gt;
&lt;td&gt;Alice Navarro&lt;/td&gt;
&lt;td&gt;new&lt;/td&gt;
&lt;td&gt;$145.96&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ord-a003&lt;/td&gt;
&lt;td&gt;tenant-alpha&lt;/td&gt;
&lt;td&gt;Clara Mendes&lt;/td&gt;
&lt;td&gt;shipped&lt;/td&gt;
&lt;td&gt;$361.99&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ord-a005&lt;/td&gt;
&lt;td&gt;tenant-alpha&lt;/td&gt;
&lt;td&gt;Elena Vasquez&lt;/td&gt;
&lt;td&gt;cancelled&lt;/td&gt;
&lt;td&gt;$129.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ord-b001&lt;/td&gt;
&lt;td&gt;tenant-beta&lt;/td&gt;
&lt;td&gt;Grace Osei&lt;/td&gt;
&lt;td&gt;new&lt;/td&gt;
&lt;td&gt;$74.97&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ord-b003&lt;/td&gt;
&lt;td&gt;tenant-beta&lt;/td&gt;
&lt;td&gt;Ingrid Sorensen&lt;/td&gt;
&lt;td&gt;shipped&lt;/td&gt;
&lt;td&gt;$249.00&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;ord-b006&lt;/td&gt;
&lt;td&gt;tenant-beta&lt;/td&gt;
&lt;td&gt;Luca Ferrari&lt;/td&gt;
&lt;td&gt;cancelled&lt;/td&gt;
&lt;td&gt;$101.97&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;Because the request is open-ended, names, values, and document counts may vary. The workflow remains the same: create the resources, load the data, and query it back. Showing the saved orders confirms that the data is in the emulator and ready for the application to use.&lt;/p&gt;

&lt;p&gt;At this point, the developer has persisted, partitioned data for integration testing without writing a seed script or manually assembling documents.&lt;/p&gt;

&lt;p&gt;Notice that the prompt describes the application need, not the operating procedure. It says nothing about finding the emulator, using the bundled shell, choosing non-interactive commands, or verifying changes.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why use an Agent Skill
&lt;/h2&gt;

&lt;p&gt;You could include all of those operating instructions in every prompt. That works for a one-off task, but repeating the same guidance soon becomes tedious. Results can also vary when an important constraint is omitted or phrased differently.&lt;/p&gt;

&lt;p&gt;Moving the guidance into global instructions avoids that repetition, but makes emulator-specific context available during unrelated tasks.&lt;/p&gt;

&lt;p&gt;An Agent Skill avoids both tradeoffs. The &lt;a href="https://github.com/abhirockzz/cosmosdb-vnext-emulator-skill" rel="noopener noreferrer"&gt;&lt;code&gt;cosmosdb-emulator-vnext&lt;/code&gt;&lt;/a&gt; skill keeps the emulator guidance in one place and makes it available when a relevant request is detected. As a Markdown file, the skill can be shared, reviewed, tested, versioned, and adapted to a team's conventions or testing workflow.&lt;/p&gt;

&lt;p&gt;The same approach extends to other parts of Cosmos DB development. The Azure Cosmos DB team maintains the &lt;a href="https://github.com/AzureCosmosDB/cosmosdb-agent-kit" rel="noopener noreferrer"&gt;Cosmos DB Agent Kit&lt;/a&gt;, a collection of skills for AI coding agents working with Cosmos DB. It includes guidance on data modeling, partition-key design, query optimization, SDK usage, indexing, throughput, security, and monitoring.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The emulator skill may also be combined into the Agent Kit and maintained there alongside other Cosmos DB skills.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Try it yourself
&lt;/h2&gt;

&lt;p&gt;Agent Skills are a lightweight, open standard that lets you reuse the same skill across coding agents.&lt;/p&gt;

&lt;p&gt;Install the skill and put it to work with your local emulator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;npx skills add abhirockzz/cosmosdb-vnext-emulator-skill
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then run the order-processing prompt above to create your first test dataset. From there, adapt the request to the data and workflows your application needs.&lt;/p&gt;

&lt;p&gt;Together, the local emulator, Cosmos DB Shell, and the skill make this kind of setup repeatable without hiding how the work gets done. Developers can describe the data they need while the agent runs explicit commands, verifies the result, and leaves an execution trail they can inspect.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>azure</category>
      <category>ai</category>
      <category>agents</category>
    </item>
    <item>
      <title>How to Use LangChain Deep Agents with Azure Cosmos DB – Plan, act, and verify against operational data</title>
      <dc:creator>Abhishek Gupta</dc:creator>
      <pubDate>Tue, 23 Jun 2026 18:26:49 +0000</pubDate>
      <link>https://dev.to/abhirockzz/how-to-use-deep-agents-with-azure-cosmos-db-plan-act-and-verify-against-operational-data-5469</link>
      <guid>https://dev.to/abhirockzz/how-to-use-deep-agents-with-azure-cosmos-db-plan-act-and-verify-against-operational-data-5469</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://devblogs.microsoft.com/cosmosdb/deep-agents-to-plan-act-verify-against-operational-data/" rel="noopener noreferrer"&gt;https://devblogs.microsoft.com/cosmosdb/deep-agents-to-plan-act-verify-against-operational-data/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://docs.langchain.com/oss/python/deepagents/overview" rel="noopener noreferrer"&gt;Deep Agents&lt;/a&gt; is an agent harness built on &lt;a href="http://docs.langchain.com/oss/python/langgraph/overview" rel="noopener noreferrer"&gt;LangGraph&lt;/a&gt;, for agents that need to work through a task over many steps instead of a single LLM call. The agent runs tools, looks at the results, and uses that to pick the next one, keeping a todo list as it goes. On top of that loop the harness brings what a longer-running agent needs. It can load instructions on demand instead of holding everything in the prompt (skills), offload large tool outputs so they don't fill the context window, and pause for human approval in apps that need an approval gate before data changes.&lt;/p&gt;

&lt;p&gt;Support Ops Agent is a sample app that puts this to work on a customer-support ticket queue. We can ask it which tickets are at risk, who's overloaded, or whether a run of similar complaints is really one outage. When a ticket needs to change, it updates the ticket and reads it back to confirm. Most requests become a handful of reads against the queue. Requests that change a ticket add a patch and a verification read.&lt;/p&gt;

&lt;p&gt;That queue lives in &lt;a href="https://learn.microsoft.com/azure/cosmos-db/nosql/" rel="noopener noreferrer"&gt;Azure Cosmos DB&lt;/a&gt;, the operational database the support team already runs on. The agent reads and writes that same store through the Azure Cosmos DB SDK, so it works on the live tickets, with no side index to keep in sync. Each ticket is an Azure Cosmos DB item, with its tags and history kept right inside it, and the agent updates that item directly. With the partition key doing its job, point reads and customer-scoped queries stay cheap. Queue-wide investigations spend RUs based on the cross-partition work they do, which is why the tools project only the fields they need. The schema is flexible, so the agent can add a tag or append to a history array without a migration.&lt;/p&gt;

&lt;p&gt;The code is on &lt;a href="https://github.com/abhirockzz/deepagents-cosmosdb-support-ops" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; with instructions to run it against your own Azure Cosmos DB account. In this post, I'll go through:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;what the agent can do, and the Azure Cosmos DB operation behind each kind of request&lt;/li&gt;
&lt;li&gt;why Deep Agents and Azure Cosmos DB fit this problem&lt;/li&gt;
&lt;li&gt;the tools it uses to work on the ticket queue&lt;/li&gt;
&lt;li&gt;practical examples of how the agent works: morning triage, resolving a ticket, and spotting an incident&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Agent capabilities
&lt;/h2&gt;

&lt;p&gt;The requests in this sample all come down to a few Azure Cosmos DB operations. Some questions only need reads. Others need the agent to read first, decide what changed, and then patch the ticket.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Ask it to…&lt;/th&gt;
&lt;th&gt;What the agent does&lt;/th&gt;
&lt;th&gt;Cosmos DB operations&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Triage the queue&lt;/td&gt;
&lt;td&gt;Finds the at-risk tickets (high priority, still active, gone stale) and reports the handful that actually matter&lt;/td&gt;
&lt;td&gt;cross-partition query, filter, ORDER BY&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Resolve a ticket&lt;/td&gt;
&lt;td&gt;Point-reads the ticket, checks related ones from the same customer, updates status, owner, and history, then re-reads to confirm&lt;/td&gt;
&lt;td&gt;point read, related-item query, update, verify&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Spot an incident&lt;/td&gt;
&lt;td&gt;Searches for a cluster across customers, including symptoms filed under the wrong area, and can tag the group as a known issue&lt;/td&gt;
&lt;td&gt;multi-step query, repeated patches&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Check queue health&lt;/td&gt;
&lt;td&gt;Summarizes the queue by status, by area, and by who is carrying the load&lt;/td&gt;
&lt;td&gt;grouped counts&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Cover for someone&lt;/td&gt;
&lt;td&gt;Takes an absent agent's active tickets and moves them to whoever has the lightest load, then confirms the rebalance&lt;/td&gt;
&lt;td&gt;grouped counts, repeated patches&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;I'll walk through the first three below. The other two use the same tools, so they are useful checks when you run the sample yourself.&lt;/p&gt;

&lt;h2&gt;
  
  
  Approach: Agentic vs Static
&lt;/h2&gt;

&lt;p&gt;Most ticket questions don't have a one-query answer. Take "is something breaking across customers." We run a query, look at what comes back, and only then know whether a second, narrower query is worth running. &lt;a href="https://docs.langchain.com/oss/python/deepagents/overview" rel="noopener noreferrer"&gt;Deep Agents&lt;/a&gt; handles exactly that kind of back-and-forth. It plans the work as a short todo list, calls tools, reads results, and decides the next step, instead of trying to answer in a single pass. It also keeps the agent's instructions lean: the role and the ticket schema stay loaded at all times, while the longer how-to guides load only when a task needs them.&lt;/p&gt;

&lt;p&gt;Every ticket is stored under its customer (&lt;code&gt;/customerId&lt;/code&gt;), so anything scoped to one customer, like reading a single ticket or pulling everything for ACME, stays inside one partition and querying it cost-effective. Queue-wide questions like triage or incident detection read across partitions instead, which is the right call when we're asking about every customer at once. The agent picks single-partition or cross-partition to match the question.&lt;/p&gt;

&lt;h3&gt;
  
  
  How it works
&lt;/h3&gt;

&lt;p&gt;Everything the agent does to the queue goes through the tools, each a thin wrapper over a single Azure Cosmos DB operation: a query, a point read, a grouped count, and a write. The agent never gets a raw database connection. It works the queue with the same handful of operations a support lead would, and decides which one each request calls for.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyy78z2npxezdi7lgk5e1.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fyy78z2npxezdi7lgk5e1.png" alt="Diagram showing a support request flowing to a Support Ops Agent that plans, acts, and verifies one tool call at a time using query, point-read, aggregation, and ticket-update tools connected to an Azure Cosmos DB for NoSQL support-ticket container partitioned by customer ID." width="800" height="783"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;run_query&lt;/code&gt; is the one the agent reaches for most. It takes a &lt;code&gt;SELECT&lt;/code&gt; and runs it cross-partition, which is what lets the agent search the whole queue. It's read-only: anything that isn't a &lt;code&gt;SELECT&lt;/code&gt; is refused, and so is a cross-partition &lt;code&gt;GROUP BY&lt;/code&gt; (more on that below). Writes have their own tool.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="nd"&gt;@tool&lt;/span&gt;
&lt;span class="k"&gt;def&lt;/span&gt; &lt;span class="nf"&gt;run_query&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;[]&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;-&amp;gt;&lt;/span&gt; &lt;span class="nb"&gt;str&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="sh"&gt;"""&lt;/span&gt;&lt;span class="s"&gt;Run a read-only Cosmos DB NoSQL SELECT over the tickets container.&lt;/span&gt;&lt;span class="sh"&gt;"""&lt;/span&gt;
    &lt;span class="n"&gt;stripped&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;strip&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="ow"&gt;not&lt;/span&gt; &lt;span class="n"&gt;stripped&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;upper&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;startswith&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;SELECT&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;):&lt;/span&gt;
        &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;Error: only SELECT queries are allowed. Use update_ticket for writes.&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;
    &lt;span class="n"&gt;items&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;_get_container&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;query_items&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
        &lt;span class="n"&gt;query&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;stripped&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;json&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;loads&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="ow"&gt;or&lt;/span&gt; &lt;span class="bp"&gt;None&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="n"&gt;enable_cross_partition_query&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="bp"&gt;True&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="p"&gt;)&lt;/span&gt;
 &lt;span class="bp"&gt;...&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;read_ticket&lt;/code&gt; is the cheap path. When the agent already knows the ticket id and the customer, it does a point read on the partition key for around 1 RU instead of running a query.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;update_ticket&lt;/code&gt; is the only way the agent writes. It patches a ticket in place, always refreshes &lt;code&gt;updatedAt&lt;/code&gt;, and appends an entry to the ticket's history array, so every change it makes stays traceable.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight python"&gt;&lt;code&gt;&lt;span class="n"&gt;ops&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;op&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;set&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;path&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sa"&gt;f&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/&lt;/span&gt;&lt;span class="si"&gt;{&lt;/span&gt;&lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="k"&gt;for&lt;/span&gt; &lt;span class="n"&gt;k&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;v&lt;/span&gt; &lt;span class="ow"&gt;in&lt;/span&gt; &lt;span class="n"&gt;fields&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;items&lt;/span&gt;&lt;span class="p"&gt;()]&lt;/span&gt;
&lt;span class="n"&gt;ops&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;op&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;set&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;path&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/updatedAt&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;history_note&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
    &lt;span class="n"&gt;ops&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;append&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;op&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;add&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;path&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;/history/-&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
        &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;value&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;at&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;now&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;by&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;history_by&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="s"&gt;note&lt;/span&gt;&lt;span class="sh"&gt;"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;history_note&lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;})&lt;/span&gt;
&lt;span class="nf"&gt;_get_container&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;patch_item&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
    &lt;span class="n"&gt;item&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ticket_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;partition_key&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;customer_id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;patch_operations&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;ops&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;aggregate_tickets&lt;/code&gt; answers the queue-health questions: how many tickets sit in each status, which area is busiest, who is carrying the most load. It counts tickets across the whole queue, grouped by a single field.&lt;/p&gt;

&lt;p&gt;You might expect that to be a plain &lt;code&gt;GROUP BY&lt;/code&gt;, and in Azure Cosmos DB's query language it is. The catch is in the SDK. The &lt;code&gt;azure-cosmos&lt;/code&gt; Python SDK runs a &lt;code&gt;GROUP BY&lt;/code&gt; fine within a single partition, but refuses one that spans partitions, returning &lt;code&gt;"Cross partition query only supports 'VALUE' for aggregates."&lt;/code&gt;&lt;/p&gt;

&lt;p&gt;The support queue spans every customer, so the grouped counts have to come some other way. &lt;code&gt;aggregate_tickets&lt;/code&gt; projects the one field across partitions and counts the values in Python instead, and &lt;code&gt;run_query&lt;/code&gt; points the agent here whenever it reaches for a &lt;code&gt;GROUP BY&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Support Ops agent in action
&lt;/h2&gt;

&lt;p&gt;I'll use three requests from the sample runs to show what that looks like. They start the way a support lead would ask them, and the agent has to turn each one into the right mix of queries, reads, and updates.&lt;/p&gt;

&lt;h3&gt;
  
  
  Morning triage
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;I just got in, what should I look at first?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;There's no single query for "what should I look at first." The agent reads it as a question about risk: which active tickets are closest to slipping. A ticket has no "at risk" field to sort by, so the agent has to decide what at-risk means and turn that into a query. It settles on the tickets that are high priority, still active, and have gone untouched for a few days, and asks Azure Cosmos DB for those, oldest first.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;customerId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;priority&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;assignee&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;updatedAt&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;priority&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'P1'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'P2'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'open'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'in-progress'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;updatedAt&lt;/span&gt; &lt;span class="o"&gt;&amp;lt;&lt;/span&gt; &lt;span class="o"&gt;@&lt;/span&gt;&lt;span class="n"&gt;staleBefore&lt;/span&gt;
&lt;span class="k"&gt;ORDER&lt;/span&gt; &lt;span class="k"&gt;BY&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;updatedAt&lt;/span&gt; &lt;span class="k"&gt;ASC&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;It doesn't stop at the list. It also runs a few grouped counts to size up the rest of the queue behind those tickets, then reports the handful that matter with a one-line reason each and a suggested order to work them:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Start with the stale high-priority active tickets:

- TICKET-1004 (UMBRELLA): P1 open, unassigned, data issue, untouched since
  Jun 5. Oldest urgent ticket in the queue.
- TICKET-1003 (INITECH): P2 open, unassigned, login lockout, untouched since
  Jun 7. Customer access issue and stale.
- TICKET-1001 (ACME): P1 open, unassigned, billing, untouched since Jun 8.
  Revenue-impacting and still idle.
- TICKET-1002 (GLOBEX): P1 in-progress, performance, with agent.lee, untouched
  since Jun 9. Already owned, but stale enough to need a status check.
- TICKET-1010 (INITECH): P2 open, unassigned, performance, untouched since
  Jun 11.

Queue health in brief: 93 active tickets (57 open, 36 in-progress), and 72 of
them are unassigned. Hottest active area is api (22), then billing (21).
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note how the user didn't define "at risk" up front – the agent had to turn that into something Azure Cosmos DB could query.&lt;/p&gt;

&lt;h3&gt;
  
  
  Resolve a ticket
&lt;/h3&gt;

&lt;p&gt;The next request names a specific ticket and expects something done about it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;GLOBEX is unhappy about TICKET-1050, can you pick it up and move it forward?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent starts with a point read on the ticket. It knows the id and the customer, so this stays inside GLOBEX's partition. The ticket comes back as a login issue, open and unassigned. Before touching it, the agent looks for context: it pulls GLOBEX's other tickets, then checks the active login tickets across the rest of the queue, and notices this isn't an isolated report. Several customers have similar authentication problems open right now.&lt;/p&gt;

&lt;p&gt;With that picture, it does the obvious thing: the ticket needs an owner and a status update. It applies the change through &lt;code&gt;update_ticket&lt;/code&gt;, which patches the fields, refreshes &lt;code&gt;updatedAt&lt;/code&gt;, and appends a history note in one write so the trail is clear.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight properties"&gt;&lt;code&gt;&lt;span class="err"&gt;status&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="err"&gt;in-progress&lt;/span&gt;
&lt;span class="err"&gt;assignee&lt;/span&gt; &lt;span class="err"&gt;→&lt;/span&gt; &lt;span class="err"&gt;agent.dana&lt;/span&gt;
&lt;span class="err"&gt;tags&lt;/span&gt; &lt;span class="err"&gt;+=&lt;/span&gt; &lt;span class="err"&gt;login,&lt;/span&gt; &lt;span class="err"&gt;auth,&lt;/span&gt; &lt;span class="err"&gt;needs-investigation&lt;/span&gt;
&lt;span class="err"&gt;history&lt;/span&gt; &lt;span class="err"&gt;+=&lt;/span&gt; &lt;span class="err"&gt;"Picked&lt;/span&gt; &lt;span class="err"&gt;up&lt;/span&gt; &lt;span class="err"&gt;after&lt;/span&gt; &lt;span class="err"&gt;customer&lt;/span&gt; &lt;span class="err"&gt;escalation;&lt;/span&gt; &lt;span class="err"&gt;flagged&lt;/span&gt; &lt;span class="err"&gt;for&lt;/span&gt; &lt;span class="err"&gt;auth&lt;/span&gt; &lt;span class="err"&gt;investigation."&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then it reads the ticket back to confirm the change landed, rather than trusting the write went through, and reports what it did and why:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;TICKET-1050 (GLOBEX) is now in progress with agent.dana assigned.

Why this move:
- It was a stale P2 login issue sitting open and unassigned.
- There are similar active login/auth tickets across other customers, so this
may be part of a broader authentication pattern rather than an isolated report.

Verified state: status in-progress, assignee agent.dana, tags
login / auth / needs-investigation, history note added.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;For &lt;code&gt;TICKET-1050&lt;/code&gt;, the agent didn't just assign an owner. It checked the customer context, looked for similar login issues, made the update, and then read the ticket back. The agent should not report a write until it has read the updated ticket and seen the new status, assignee, tags, and history note.&lt;/p&gt;

&lt;h3&gt;
  
  
  Spot an incident
&lt;/h3&gt;

&lt;p&gt;Now try a login related request that starts broad:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Logins feel shaky this week, dig in and flag anything related.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent pulls in its incident-search guide before it starts querying. Its first pass is the obvious one: active tickets in the login area. That catches part of the problem, but not all of it. People describe the same symptom in different words, and some login tickets land under another area. So the agent runs a second query against the ticket text, looking for authentication symptoms that landed somewhere else.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;id&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;title&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;area&lt;/span&gt; &lt;span class="o"&gt;!=&lt;/span&gt; &lt;span class="s1"&gt;'login'&lt;/span&gt; &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;status&lt;/span&gt; &lt;span class="k"&gt;IN&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;'open'&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="s1"&gt;'in-progress'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="k"&gt;AND&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;CONTAINS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;LOWER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'authentication'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="k"&gt;CONTAINS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;LOWER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'sign in'&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
       &lt;span class="k"&gt;OR&lt;/span&gt; &lt;span class="k"&gt;CONTAINS&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;LOWER&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;description&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt; &lt;span class="s1"&gt;'log in'&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;That second query turns up TICKET-1052 (STARK), filed under other as "Authentication errors on mobile app", which an &lt;code&gt;area = 'login'&lt;/code&gt; filter would have missed entirely. A few more queries (grouped counts by customer, and a check on how recent these are) confirm the issue:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;There is a real login/auth cluster.

7 active tickets across 6 customers, 6 of them created this week and 4 landed on
Jun 13 alone. The most urgent:

- TICKET-1051 (HOOLI): P1 open, "Multiple users can't log in this morning"
- TICKET-1053 (UMBRELLA): P2 open, "SSO login broken after update"
- TICKET-1052 (STARK): P2 open, area `other`, "Authentication errors on mobile app"
- TICKET-1050 (GLOBEX): P2 open, "Cannot sign in - authentication failing"
- TICKET-1042 (ACME): P2 open, "Unable to log in after MFA enabled"

One relevant ticket is misfiled under `other`, so a pure area = 'login' view
undercounts the issue.

If you want, I can tag these 7 with a shared marker like known-issue:login-surge
so the cluster is easier to track.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Tagging seven tickets is different from updating one, so the agent stops and asks first. If the user confirms, it could have made the &lt;code&gt;update_ticket&lt;/code&gt; patch on each one, append the tag and a history note. The login surge only becomes visible after the active-login query, the text search, the customer counts, and the dates are looked at together.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it, and build your own
&lt;/h2&gt;

&lt;p&gt;The repo has everything to run this against your own Azure Cosmos DB account: the tools, the seed data, and a CLI that streams each step as the agent works. The &lt;a href="https://github.com/abhirockzz/deepagents-cosmosdb-support-ops/blob/main/README.md" rel="noopener noreferrer"&gt;README&lt;/a&gt; walks through setup and the az login auth. Run &lt;code&gt;python seed.py&lt;/code&gt; to load the support queue data, then replay the runs above or ask the agent your own questions.&lt;/p&gt;

&lt;p&gt;Once you have the sample running, try the same idea with data from one of your own workflows. Start with read-only questions and watch how the agent breaks them into Azure Cosmos DB operations. Then add scoped writes when the boundary is clear: what the agent can change, what history it should leave, and how it verifies the result. That could be support tickets, incidents, orders, devices, or any other operational data where a multi-step agent can help.&lt;/p&gt;

&lt;h2&gt;
  
  
  Learn more
&lt;/h2&gt;

&lt;ul&gt;
&lt;li&gt;For the agent framework, start with the &lt;a href="https://docs.langchain.com/oss/python/deepagents/overview" rel="noopener noreferrer"&gt;Deep Agents docs&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/azure/cosmos-db/ai-agents" rel="noopener noreferrer"&gt;AI agents in Azure Cosmos DB&lt;/a&gt; is a good place to step back and review the broader agent concepts: planning, tool use, memory, copilots, autonomous agents, and multi-agent systems.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/azure/cosmos-db/gen-ai/agentic-retrieval" rel="noopener noreferrer"&gt;Agentic Retrieval Toolkit&lt;/a&gt; shows how to ground answers with multi-step retrieval over Cosmos DB data&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/azure/cosmos-db/gen-ai/agent-memory-toolkit" rel="noopener noreferrer"&gt;Agent Memory Toolkit&lt;/a&gt; covers durable agent memory backed by Cosmos DB.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/azure/cosmos-db/gen-ai/model-context-protocol-toolkit" rel="noopener noreferrer"&gt;MCP Toolkit for Azure Cosmos DB&lt;/a&gt; shows another way to expose Cosmos DB capabilities to agentic applications.&lt;/li&gt;
&lt;/ul&gt;

</description>
      <category>agents</category>
      <category>python</category>
      <category>langchain</category>
      <category>rag</category>
    </item>
    <item>
      <title>Announcing General availability of the Azure Cosmos DB vNext emulator</title>
      <dc:creator>Abhishek Gupta</dc:creator>
      <pubDate>Tue, 23 Jun 2026 18:15:41 +0000</pubDate>
      <link>https://dev.to/abhirockzz/announcing-general-availability-of-the-azure-cosmos-db-vnext-emulator-13ip</link>
      <guid>https://dev.to/abhirockzz/announcing-general-availability-of-the-azure-cosmos-db-vnext-emulator-13ip</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://devblogs.microsoft.com/cosmosdb/announcing-general-availability-of-the-azure-cosmos-db-vnext-emulator/" rel="noopener noreferrer"&gt;https://devblogs.microsoft.com/cosmosdb/announcing-general-availability-of-the-azure-cosmos-db-vnext-emulator/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;The Azure Cosmos DB vNext emulator is generally available today. It ships as a Docker image that runs on Linux, macOS, and Windows, on both x64 and ARM64 architectures, giving you a local Cosmos DB instance you can develop and test against. Use it for inner-loop development on your laptop, in CI integration tests, and anywhere else you'd rather not use a live account.&lt;/p&gt;

&lt;p&gt;You can get started right away with a couple of simple commands:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker pull mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-latest

docker run &lt;span class="nt"&gt;-p&lt;/span&gt; 8081:8081 &lt;span class="nt"&gt;-p&lt;/span&gt; 8080:8080 &lt;span class="nt"&gt;-p&lt;/span&gt; 1234:1234 mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A lot has shipped since the preview announcement: broader feature and API coverage, an embedded shell, vector search, and OpenTelemetry support. The rest of this post walks through what's new at GA and how to use it.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/qcmpIIKzfII"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Bootstrap and explore data with the bundled Azure Cosmos DB Shell
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://learn.microsoft.com/azure/cosmos-db/shell/overview" rel="noopener noreferrer"&gt;Azure Cosmos DB Shell&lt;/a&gt; is an open-source CLI for interacting with Azure Cosmos DB using bash-like commands. It's now bundled inside the emulator image, so you can drop into an interactive session against a running container without installing anything separately:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec&lt;/span&gt; &lt;span class="nt"&gt;-it&lt;/span&gt; &amp;lt;container-name&amp;gt; cosmoshell.sh
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The wrapper auto-detects the emulator endpoint and authenticates with the well-known account key.&lt;/p&gt;

&lt;p&gt;Before this, getting a known dataset into the emulator usually meant an extra script in your test setup: wait for the gateway to come up, then create databases, containers, and seed documents. Thanks to the Azure Cosmos DB Shell integration, the emulator runs any &lt;code&gt;.csh&lt;/code&gt; scripts at the top level of &lt;code&gt;/init&lt;/code&gt; in alphabetical order before the emulator is ready to accept requests. The bootstrap step moves out of your application and into the container itself.&lt;/p&gt;

&lt;p&gt;This is useful for many scenarios, including:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CI integration tests.&lt;/strong&gt; Every job starts from an identical, deterministic dataset, with no app-side bootstrap and no readiness polling.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Local dev reset.&lt;/strong&gt; Pair &lt;code&gt;--rm&lt;/code&gt; with an &lt;code&gt;/init&lt;/code&gt; folder for a one-command reset back to a known state between runs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Demos and tutorials.&lt;/strong&gt; Ship fixture scripts next to your sample so readers see real data on first run, not an empty database.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Bug repros.&lt;/strong&gt; Capture a problematic dataset as a small folder of scripts and attach it to an issue.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The example below sets up a &lt;code&gt;ShopDB&lt;/code&gt; with &lt;code&gt;Users&lt;/code&gt; and &lt;code&gt;Orders&lt;/code&gt; containers, both partitioned on &lt;code&gt;/customerId&lt;/code&gt; so a customer's orders co-locate with their profile. It uses separate scripts for each step.&lt;/p&gt;

&lt;p&gt;&lt;code&gt;01-init.csh&lt;/code&gt; creates the database and both containers. Adding &lt;code&gt;cd ShopDB&lt;/code&gt; at the end means later scripts don't have to repeat &lt;code&gt;--database=ShopDB&lt;/code&gt; on every line, since the shell session is shared across files.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mkdb ShopDB
mkcon Users /customerId &lt;span class="nt"&gt;--database&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ShopDB
mkcon Orders /customerId &lt;span class="nt"&gt;--database&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;ShopDB
&lt;span class="nb"&gt;cd &lt;/span&gt;ShopDB
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;code&gt;02-load.csh&lt;/code&gt; inserts a couple of users and a few of their orders:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mkitem &lt;span class="nt"&gt;-container&lt;/span&gt; Users &lt;span class="s1"&gt;'{"id":"u1","customerId":"u1","name":"Alice","tier":"gold"}'&lt;/span&gt;
mkitem &lt;span class="nt"&gt;-container&lt;/span&gt; Users &lt;span class="s1"&gt;'{"id":"u2","customerId":"u2","name":"Bob","tier":"silver"}'&lt;/span&gt;
mkitem &lt;span class="nt"&gt;-container&lt;/span&gt; Orders &lt;span class="s1"&gt;'{"id":"o1","customerId":"u1","total":129.50,"status":"shipped"}'&lt;/span&gt;
mkitem &lt;span class="nt"&gt;-container&lt;/span&gt; Orders &lt;span class="s1"&gt;'{"id":"o2","customerId":"u1","total":42.00,"status":"pending"}'&lt;/span&gt;
mkitem &lt;span class="nt"&gt;-container&lt;/span&gt; Orders &lt;span class="s1"&gt;'{"id":"o3","customerId":"u2","total":18.75,"status":"shipped"}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Mount the folder at &lt;code&gt;/init&lt;/code&gt; and start the container:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--name&lt;/span&gt; emulator &lt;span class="nt"&gt;--rm&lt;/span&gt; &lt;span class="nt"&gt;-e&lt;/span&gt; &lt;span class="nv"&gt;ENABLE_INIT_DATA&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-v&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;&lt;span class="nb"&gt;pwd&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;:/init"&lt;/span&gt; &lt;span class="nt"&gt;-p&lt;/span&gt; 8081:8081 &lt;span class="nt"&gt;-p&lt;/span&gt; 1234:1234 &lt;span class="se"&gt;\&lt;/span&gt;
mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;By the time the emulator is up, both containers are populated and queryable. Verify with a one-liner that pulls Alice's orders:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker &lt;span class="nb"&gt;exec &lt;/span&gt;emulator cosmoshell.sh &lt;span class="nt"&gt;-c&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="s1"&gt;'query "SELECT c.id, c.total, c.status FROM c WHERE c.customerId = '&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="s1"&gt;'u1'&lt;/span&gt;&lt;span class="se"&gt;\'&lt;/span&gt;&lt;span class="s1"&gt;'" --container=Orders --database=ShopDB'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you just want a quick look without writing any scripts, the image also ships with example seed scripts under &lt;code&gt;/scripts/init_examples/&lt;/code&gt; that load automatically when &lt;code&gt;ENABLE_INIT_DATA=true&lt;/code&gt; is set. Or, if you need the seeded state to survive container restarts, bind-mount a host folder at &lt;code&gt;/data&lt;/code&gt; and the emulator will skip initialization on subsequent runs. The &lt;a href="https://learn.microsoft.com/azure/cosmos-db/emulator-linux#use-azure-cosmos-db-shell-with-the-emulator" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; has the full set of options.&lt;/p&gt;

&lt;h2&gt;
  
  
  Vector search for local AI development
&lt;/h2&gt;

&lt;p&gt;The emulator supports &lt;a href="https://learn.microsoft.com/azure/cosmos-db/vector-search" rel="noopener noreferrer"&gt;vector search&lt;/a&gt;, so you can build and iterate on RAG and semantic-search workloads locally. Define a vector embedding policy on the container, add a matching vector index, and write the embedding alongside the rest of your document:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"vectorEmbeddingPolicy"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="nl"&gt;"vectorEmbeddings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/embedding"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"dataType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"float32"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"distanceFunction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cosine"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"dimensions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1024&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then, you can execute semantic search queries using the &lt;a href="https://learn.microsoft.com/azure/cosmos-db/nosql/query/vectordistance" rel="noopener noreferrer"&gt;VectorDistance()&lt;/a&gt; function to get results ranked by similarity. Paired with a model running on your laptop, embeddings, storage, and retrieval all stay on the machine, which is handy when you're iterating on your application.&lt;/p&gt;

&lt;p&gt;Try out this sample that embeds and loads data into the emulator. It uses &lt;a href="https://www.langchain.com/" rel="noopener noreferrer"&gt;LangChain&lt;/a&gt;, a popular open-source framework for building AI applications, and &lt;a href="https://ollama.com/" rel="noopener noreferrer"&gt;Ollama&lt;/a&gt;, a tool for running open-source models locally.&lt;/p&gt;

&lt;p&gt;You'll need Python 3.x, and Ollama installed locally.&lt;/p&gt;

&lt;p&gt;Start by running the emulator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker run &lt;span class="nt"&gt;--detach&lt;/span&gt; &lt;span class="nt"&gt;--name&lt;/span&gt; emulator &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;-p&lt;/span&gt; 8081:8081 &lt;span class="nt"&gt;-p&lt;/span&gt; 1234:1234 &lt;span class="se"&gt;\&lt;/span&gt;
mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install Ollama, start the local server, and pull &lt;code&gt;mxbai-embed-large&lt;/code&gt;. It produces 1024-dimension embeddings and is small enough to run comfortably on a developer laptop:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-fsSL&lt;/span&gt; https://ollama.com/install.sh | sh
ollama serve &amp;amp;
ollama pull mxbai-embed-large
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Clone the sample and install its dependencies in a virtual environment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/abhirockzz/cosmosdb-emulator-local-vector-search-example

&lt;span class="nb"&gt;cd &lt;/span&gt;cosmosdb-emulator-local-vector-search-example

python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The sample reads its database name, container name, and embedding model from environment variables:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DATABASE_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"docsdb"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;CONTAINER_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"docs"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;EMBEDDINGS_MODEL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"mxbai-embed-large"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;EMBEDDING_DIMENSIONS&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"1024"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now load the data. &lt;code&gt;load_data.py&lt;/code&gt; fetches two Azure Cosmos DB documentation pages, splits them into Markdown chunks with LangChain, embeds each chunk with Ollama, and writes the chunks plus their vectors into the emulator. The container is created on first run with a vector embedding policy (&lt;code&gt;/embedding&lt;/code&gt;, &lt;code&gt;float32&lt;/code&gt;, &lt;code&gt;cosine&lt;/code&gt; distance) and a DiskANN vector index.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 load_data.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;With the data loaded, you can run vector queries. &lt;code&gt;vector_search.py&lt;/code&gt; takes a natural-language query, embeds it with the same local model, and runs a &lt;code&gt;VectorDistance()&lt;/code&gt; query against the emulator container to return the top-k matching chunks by cosine similarity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 vector_search.py &lt;span class="s2"&gt;"show me an example of a vector embedding policy"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll get back the most semantically relevant chunks of the source documentation, ordered by score. Try a few more queries to get a feel for what the index is doing:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python3 vector_search.py &lt;span class="s2"&gt;"how do I tune recall vs latency for vector queries"&lt;/span&gt;
python3 vector_search.py &lt;span class="s2"&gt;"best practices for multi-tenant vector workloads"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Other improvements
&lt;/h2&gt;

&lt;p&gt;Beyond the shell and vector search, a handful of other improvements round out the GA release and make the emulator easier to plug into real workflows.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Health probe endpoint&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The emulator exposes dedicated health endpoints on port &lt;code&gt;8080&lt;/code&gt;: &lt;code&gt;/alive&lt;/code&gt; for liveness, &lt;code&gt;/ready&lt;/code&gt; for readiness, and &lt;code&gt;/status&lt;/code&gt; for detailed status.&lt;/p&gt;

&lt;p&gt;Previously, tests, CI jobs and other components depended on the &lt;code&gt;System is now fully ready to accept requests&lt;/code&gt; log line to know when the gateway was up. That works but is brittle. An HTTP probe is a better fit. The legacy log message is still emitted for backward compatibility, but we recommend moving to the probe.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;OpenTelemetry support&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The emulator supports the &lt;a href="https://opentelemetry.io/" rel="noopener noreferrer"&gt;OpenTelemetry Protocol (OTLP)&lt;/a&gt; for exporting telemetry. With &lt;code&gt;--enable-otlp&lt;/code&gt; (or &lt;code&gt;ENABLE_OTLP_EXPORTER=true&lt;/code&gt;), it emits request rates, query execution times, resource utilization, and error rates that you can pipe into any OTLP-compatible backend. For quick debugging without a collector, &lt;code&gt;--enable-console&lt;/code&gt; (or &lt;code&gt;ENABLE_CONSOLE_EXPORTER=true&lt;/code&gt;) prints telemetry to stdout. Conditional TLS is supported on the OTLP exporter, so the emulator can be wired into observability stacks that require secure transport. Detailed setup and examples &lt;a href="https://github.com/Azure/azure-cosmos-db-emulator-docker/blob/master/docs/opentelemetry.md" rel="noopener noreferrer"&gt;live in the GitHub repo&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Broader feature and API coverage&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The emulator is designed to be used with the standard Azure Cosmos DB SDKs and supports common local development scenarios. The supported API surface has grown to cover common app requirements: change feed, batch operations, &lt;code&gt;JOIN&lt;/code&gt;s, range and aggregate queries, subdocument queries, hierarchical partition keys, &lt;code&gt;TTL&lt;/code&gt;, and an expanded set of string and array operators.&lt;/p&gt;

&lt;p&gt;For example, you can now query deeply nested properties and guard against missing fields in a single statement:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;username&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;phone&lt;/span&gt;
&lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt;
&lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;IS_DEFINED&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;profile&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;contact&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;See the &lt;a href="https://devblogs.microsoft.com/cosmosdb/azure-cosmos-db-vnext-emulator-query-and-observability-enhancements/" rel="noopener noreferrer"&gt;preview enhancements post&lt;/a&gt; for more query walkthroughs across JOINs, operators, and subdocuments.&lt;/p&gt;

&lt;p&gt;A few endpoints that aren't core to data operations (offers, users, permissions, etc.) are now accepted as no-ops. They return valid HTTP status codes but don't perform the underlying operation, so application code that happens to touch them won't break when pointed at the emulator.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get started
&lt;/h2&gt;

&lt;p&gt;The Azure Cosmos DB Linux emulator is generally available today. Pull the GA image and you have a local Azure Cosmos DB endpoint to develop and test against, right on your machine and without an Azure subscription.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;docker pull mcr.microsoft.com/cosmosdb/linux/azure-cosmos-emulator:vnext-latest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If you hit an issue or have a feature request, please open it on the &lt;a href="https://github.com/Azure/azure-cosmos-db-emulator-docker/issues" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>docker</category>
      <category>azure</category>
      <category>database</category>
      <category>python</category>
    </item>
    <item>
      <title>Introducing OmniVec: An Open-Source Embedding Platform for AI Apps on Azure</title>
      <dc:creator>Abhishek Gupta</dc:creator>
      <pubDate>Tue, 23 Jun 2026 18:13:38 +0000</pubDate>
      <link>https://dev.to/abhirockzz/introducing-omnivec-an-open-source-embedding-platform-for-ai-apps-on-azure-216</link>
      <guid>https://dev.to/abhirockzz/introducing-omnivec-an-open-source-embedding-platform-for-ai-apps-on-azure-216</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://devblogs.microsoft.com/cosmosdb/introducing-omnivec-an-open-source-embedding-platform-for-ai-apps-on-azure/" rel="noopener noreferrer"&gt;https://devblogs.microsoft.com/cosmosdb/introducing-omnivec-an-open-source-embedding-platform-for-ai-apps-on-azure/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;Today we are open-sourcing &lt;a href="https://github.com/AzureCosmosDB/OmniVec" rel="noopener noreferrer"&gt;OmniVec&lt;/a&gt;, a platform for building and operating the embedding pipelines that keep the vector representation of your operational data in sync as it changes. You register data sources, embedding model(s), vector stores (destination), and OmniVec does the rest: initial backfill, change tracking, model invocation to generate, and writing them back to your vector store. We are shipping this with support for &lt;a href="https://learn.microsoft.com/azure/cosmos-db/" rel="noopener noreferrer"&gt;Azure Cosmos DB&lt;/a&gt;, PostgreSQL, SQL Server (source and destination), and &lt;a href="https://learn.microsoft.com/azure/storage/blobs/" rel="noopener noreferrer"&gt;Azure Blob Storage&lt;/a&gt; (destination). You deploy OmniVec in your own Azure subscription, and use the web UI, CLI, or the REST API to manage it.&lt;/p&gt;

&lt;p&gt;Most AI applications end up building the same plumbing to keep that vector representation in sync: a change-capture process on the source, a consumer pool that generates embeddings, retry and backfill logic, dead-letter handling, and the operational work to keep it all running. OmniVec collapses that stack into four configurable components: a source, a model, a destination, and a pipeline that wires the first three together.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/GnAI60YO75Q"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  Deep Dive
&lt;/h2&gt;

&lt;p&gt;Deploying OmniVec into your Azure subscription provisions multiple Azure resources, including an &lt;a href="https://learn.microsoft.com/azure/aks/" rel="noopener noreferrer"&gt;Azure Kubernetes Service&lt;/a&gt; (AKS) cluster that hosts the OmniVec services (API, controller, and workers), an Azure Cosmos DB account for pipeline metadata, job state, and progress metrics, and an &lt;a href="https://learn.microsoft.com/azure/container-registry/" rel="noopener noreferrer"&gt;Azure Container Registry&lt;/a&gt; that stores the service images AKS pulls from, and more. You control the choices that affect cost and capacity, such as the embedding model (hosted Azure OpenAI or a self-hosted GPU model), the AKS node size and count, and whether to provision a GPU pool, etc.&lt;/p&gt;

&lt;h3&gt;
  
  
  Key concepts
&lt;/h3&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbonwxm8741ke9g7n8qor.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fbonwxm8741ke9g7n8qor.png" alt=" " width="800" height="510"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;OmniVec exposes the following core primitives:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Source:&lt;/strong&gt; A system OmniVec reads records from. The source definition tells OmniVec how to connect to it and how to track changes on it.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model:&lt;/strong&gt; The embedding model OmniVec calls to turn record content into a vector. A model registration captures the provider, model name, endpoint, and credentials, and the runtime calls it with batching and retries.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Destination:&lt;/strong&gt; A vector store where the generated embeddings are written, alongside (or as an update to) the originating record.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Pipeline:&lt;/strong&gt; The binding that ties a source, a model, and a destination together. It also declares which source fields to embed and which destination field receives the vector.&lt;/li&gt;
&lt;/ul&gt;

&lt;h3&gt;
  
  
  Architecture at a glance
&lt;/h3&gt;

&lt;p&gt;OmniVec runs as a set of services on Azure Kubernetes Service:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;REST API:&lt;/strong&gt; A FastAPI control plane that holds the configuration of sources, models, destinations, and pipelines, and exposes it over REST. The CLI and the web UI use this API behind the scenes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Ingestion:&lt;/strong&gt; Watches each source for changes and queues up the records that need embedding. How it tracks changes depends on the source: the change feed for Azure Cosmos DB, blob events for Azure Blob Storage, and CDC for SQL Server and PostgreSQL.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Workers:&lt;/strong&gt; A horizontally scalable pool on compute that pulls records off the queue, calls the embedding model, and writes the resulting embedding to the destination.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Model routing layer:&lt;/strong&gt; A unified entry point in front of the embedding models. It lets a pipeline call either an external provider like &lt;a href="https://learn.microsoft.com/azure/ai-services/openai/" rel="noopener noreferrer"&gt;Azure OpenAI&lt;/a&gt; or a self-hosted GPU model.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Metadata store:&lt;/strong&gt; An Azure Cosmos DB account that the deployment provisions for you. It holds pipeline definitions, job state, progress metrics, etc.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  OmniVec in action
&lt;/h2&gt;

&lt;p&gt;Let's put OmniVec to work end to end. In this walkthrough, you will:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;deploy it into your subscription&lt;/li&gt;
&lt;li&gt;point it at an Azure Cosmos DB container&lt;/li&gt;
&lt;li&gt;wire up a pipeline to automatically generate vector embeddings&lt;/li&gt;
&lt;li&gt;then run vector search over this data&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We use Azure Cosmos DB as both the source and the destination here as an example, but this applies to any supported combination of sources, models, and destinations.&lt;/p&gt;

&lt;h3&gt;
  
  
  Prerequisites
&lt;/h3&gt;

&lt;p&gt;Before you start, make sure you have:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;An Azure subscription with permissions to create resource groups, an AKS cluster, an ACR, and an Azure Cosmos DB account.&lt;/li&gt;
&lt;li&gt;An embedding model. This walkthrough uses an &lt;a href="https://learn.microsoft.com/azure/foundry-classic/foundry-models/concepts/models-sold-directly-by-azure?tabs=americas%2Caz-global-standard%2Cglobal-standard&amp;amp;pivots=azure-openai#embeddings" rel="noopener noreferrer"&gt;Azure OpenAI embedding model deployed in Microsoft Foundry&lt;/a&gt;. &lt;a href="https://learn.microsoft.com/azure/foundry-classic/openai/how-to/create-resource?pivots=cli#deploy-a-model" rel="noopener noreferrer"&gt;Deploy one in your subscription&lt;/a&gt; and note the endpoint, model name, and API key. You'll configure them in OmniVec later.&lt;/li&gt;
&lt;li&gt;CLI tools:

&lt;ul&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/azure/developer/azure-developer-cli/install-azd" rel="noopener noreferrer"&gt;Azure Developer CLI (azd)&lt;/a&gt; for deployment.&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://learn.microsoft.com/cli/azure/install-azure-cli" rel="noopener noreferrer"&gt;Azure CLI (az)&lt;/a&gt; to setup Azure Cosmos DB (but you can also do it directly via the Azure portal).&lt;/li&gt;
&lt;li&gt;
&lt;a href="https://kubernetes.io/docs/tasks/tools/" rel="noopener noreferrer"&gt;kubectl&lt;/a&gt; and &lt;a href="https://helm.sh/docs/intro/install/" rel="noopener noreferrer"&gt;Helm&lt;/a&gt;
&lt;/li&gt;
&lt;li&gt;OmniVec CLI from the &lt;a href="https://github.com/AzureCosmosDB/OmniVec/releases" rel="noopener noreferrer"&gt;OmniVec releases page&lt;/a&gt; to manage sources, destinations, pipeline, and config.&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Then clone the quickstart repo, which has the sample data and seed script used later:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/AzureCosmosDB/omnivec-cosmosdb-quickstart

&lt;span class="nb"&gt;cd &lt;/span&gt;omnivec-cosmosdb-quickstart
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Deploy and configure OmniVec
&lt;/h3&gt;

&lt;p&gt;Create a new &lt;code&gt;azd&lt;/code&gt; environment for the deployment. Pick an &lt;code&gt;ENV_NAME&lt;/code&gt; (it becomes part of resource names), and choose a &lt;code&gt;LOCATION&lt;/code&gt; that supports AKS and Azure Cosmos DB in your subscription:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ENV_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"my-omnivec"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;LOCATION&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"westus2"&lt;/span&gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SUBSCRIPTION_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;"&amp;lt;your-subscription-id&amp;gt;"&lt;/span&gt;

azd &lt;span class="nb"&gt;env &lt;/span&gt;new &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$ENV_NAME&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--location&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$LOCATION&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--subscription&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SUBSCRIPTION_ID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Configure the deployment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;azd &lt;span class="nb"&gt;env set &lt;/span&gt;OMNIVEC_METADATA_STORE &lt;span class="s2"&gt;"cosmosdb-provisioned"&lt;/span&gt;
azd &lt;span class="nb"&gt;env set &lt;/span&gt;OMNIVEC_ENABLE_BLOB_SOURCE &lt;span class="s2"&gt;"false"&lt;/span&gt;
azd &lt;span class="nb"&gt;env set &lt;/span&gt;OMNIVEC_SYSTEM_NODE_VM_SIZE &lt;span class="s2"&gt;"Standard_D2ds_v5"&lt;/span&gt;
azd &lt;span class="nb"&gt;env set &lt;/span&gt;OMNIVEC_SYSTEM_NODE_COUNT 2
azd &lt;span class="nb"&gt;env set &lt;/span&gt;OMNIVEC_GPU_NODE_VM_SIZE &lt;span class="s2"&gt;""&lt;/span&gt;
azd &lt;span class="nb"&gt;env set &lt;/span&gt;OMNIVEC_GPU_NODE_COUNT 0
azd &lt;span class="nb"&gt;env set &lt;/span&gt;OMNIVEC_BUILD_MODE &lt;span class="s2"&gt;"acr"&lt;/span&gt;
azd &lt;span class="nb"&gt;env set &lt;/span&gt;OMNIVEC_BUILD &lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;OMNIVEC_METADATA_STORE&lt;/code&gt; provisions a dedicated Azure Cosmos DB account for OmniVec's own pipeline metadata, job state, and progress metrics.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;OMNIVEC_ENABLE_BLOB_SOURCE&lt;/code&gt; is off because this walkthrough only uses Azure Cosmos DB as a source; turn it on if you need Azure Blob Storage.&lt;/li&gt;
&lt;li&gt;Size the AKS system pool with &lt;code&gt;OMNIVEC_SYSTEM_NODE_VM_SIZE&lt;/code&gt; and &lt;code&gt;OMNIVEC_SYSTEM_NODE_COUNT&lt;/code&gt; based on your expected workload.&lt;/li&gt;
&lt;li&gt;The GPU pool (&lt;code&gt;OMNIVEC_GPU_NODE_VM_SIZE&lt;/code&gt;, &lt;code&gt;OMNIVEC_GPU_NODE_COUNT&lt;/code&gt;) is empty here because we're calling a hosted Azure OpenAI model; set them if you want to run self-hosted embedding models inside the cluster.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;OMNIVEC_BUILD_MODE=acr&lt;/code&gt; builds the service images in the provisioned ACR, and &lt;code&gt;OMNIVEC_BUILD=true&lt;/code&gt; triggers that build as part of this deployment.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;You only need one command for deployment:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;azd up
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;This takes a few minutes. It provisions the AKS cluster, Azure Cosmos DB account, and ACR, builds the OmniVec service images in ACR, and installs the Helm chart onto the cluster. When it finishes, you'll see a summary similar to the following (your values will differ):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//..... redacted
Instance ID: my-omnivec-dhmzlhlv4lk7s
Environment: my-omnivec
AKS Cluster: omnivec-aks-dhmzlhlv4lk7s
ACR Registry: omnivecacrdhmzlhlv4lk7s.azurecr.io
CosmosDB: https://omnivec-cosmos-dhmzlhlv4lk7s.documents.azure.com:443/
Admin Token: &amp;lt;admin-token&amp;gt;

OmniVec FQDN: http://my-omnivec-dhmzlhlv4lk7s.westus2.cloudapp.azure.com/ui
OmniVec IP: http://&amp;lt;public-ip&amp;gt;/ui

Health Check: http://my-omnivec-dhmzlhlv4lk7s.westus2.cloudapp.azure.com/health
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Save the admin token and the OmniVec FQDN. You'll use both in the next step to point the CLI at this deployment. You can also open the FQDN in a browser to confirm the web UI is up.&lt;/p&gt;

&lt;p&gt;The rest of this walkthrough uses the CLI (the web UI exposes the same operations if you prefer to click through it). Point it at your deployment and authenticate:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SERVER_URL&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;e.g. http://my-omnivec-dhmzlhlv4lk7s.westus2.cloudapp.azure.com/&amp;gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;ADMIN_TOKEN&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;admin-token&amp;gt;

omnivec config &lt;span class="nb"&gt;set &lt;/span&gt;server &lt;span class="nv"&gt;$SERVER_URL&lt;/span&gt;
omnivec auth login &lt;span class="nt"&gt;--token&lt;/span&gt; &lt;span class="nv"&gt;$ADMIN_TOKEN&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use the bare FQDN, without the &lt;code&gt;/ui&lt;/code&gt; suffix.&lt;/p&gt;

&lt;p&gt;Confirm the CLI is wired up:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;omnivec config view
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Finally, register your Azure OpenAI embedding model with OmniVec. Pipelines reference models by the name you give them here:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;FOUNDRY_ENDPOINT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;your-foundry-endpoint&amp;gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;FOUNDRY_MODEL_NAME&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;e.g. text-embedding-3-small&amp;gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;FOUNDRY_API_KEY&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;your-foundry-api-key&amp;gt;

omnivec model add &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--name&lt;/span&gt; demo-foundry-oai-model &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--type&lt;/span&gt; azure-openai &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--model&lt;/span&gt; &lt;span class="nv"&gt;$FOUNDRY_MODEL_NAME&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--endpoint&lt;/span&gt; &lt;span class="nv"&gt;$FOUNDRY_ENDPOINT&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--api-key&lt;/span&gt; &lt;span class="nv"&gt;$FOUNDRY_API_KEY&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Set up Azure Cosmos DB
&lt;/h3&gt;

&lt;p&gt;You need an Azure Cosmos DB account, database, and container that OmniVec will read from and write embeddings to. This walkthrough uses the same container as both source and destination. If you don't already have an Azure Cosmos DB account, &lt;a href="https://learn.microsoft.com/azure/cosmos-db/nosql/quickstart-portal#create-account" rel="noopener noreferrer"&gt;create one&lt;/a&gt; before continuing.&lt;/p&gt;

&lt;p&gt;Sign in to the Azure CLI and select the subscription that holds the account:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;az login
az account &lt;span class="nb"&gt;set&lt;/span&gt; &lt;span class="nt"&gt;--subscription&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$SUBSCRIPTION_ID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Your signed-in user needs permission to create a database and container on the account. The built-in &lt;code&gt;Cosmos DB Operator&lt;/code&gt; role (or any role granting &lt;code&gt;Microsoft.DocumentDB/databaseAccounts/sqlDatabases/*&lt;/code&gt; and &lt;code&gt;.../containers/*&lt;/code&gt; write actions) is sufficient. Account &lt;code&gt;Contributor&lt;/code&gt; or &lt;code&gt;Owner&lt;/code&gt; also works.&lt;/p&gt;

&lt;p&gt;Set the names you'll use throughout the rest of the walkthrough:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;RG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;your-resource-group&amp;gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;COSMOS_ACCOUNT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;your-cosmos-account&amp;gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;COSMOS_DB&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;omnivec-demodb
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;COSMOS_CONTAINER&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;demo-container
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create the database:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;az cosmosdb sql database create &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--account-name&lt;/span&gt; &lt;span class="nv"&gt;$COSMOS_ACCOUNT&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--resource-group&lt;/span&gt; &lt;span class="nv"&gt;$RG&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$COSMOS_DB&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create the container with a vector embedding policy and a DiskANN vector index on &lt;code&gt;/embedding&lt;/code&gt;. The &lt;code&gt;1536&lt;/code&gt; dimension matches &lt;code&gt;text-embedding-3-small&lt;/code&gt;; change it if you registered a different model:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;az cosmosdb sql container create &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--account-name&lt;/span&gt; &lt;span class="nv"&gt;$COSMOS_ACCOUNT&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--resource-group&lt;/span&gt; &lt;span class="nv"&gt;$RG&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--database-name&lt;/span&gt; &lt;span class="nv"&gt;$COSMOS_DB&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--name&lt;/span&gt; &lt;span class="nv"&gt;$COSMOS_CONTAINER&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--partition-key-path&lt;/span&gt; /id &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--vector-embeddings&lt;/span&gt; &lt;span class="s1"&gt;'{"vectorEmbeddings":[{"path":"/embedding","dataType":"float32","dimensions":1536,"distanceFunction":"cosine"}]}'&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--idx&lt;/span&gt; &lt;span class="s1"&gt;'{"indexingMode":"consistent","automatic":true,"includedPaths":[{"path":"/*"}],"excludedPaths":[{"path":"/\"_etag\"/?"},{"path":"/embedding/*"}],"vectorIndexes":[{"path":"/embedding","type":"diskANN"}]}'&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now seed it with sample data. The seed script uses &lt;code&gt;DefaultAzureCredential&lt;/code&gt;, so first grant your signed-in user the &lt;code&gt;Cosmos DB Built-in Data Contributor&lt;/code&gt; role on the Azure Cosmos DB account:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;USER_PRINCIPAL_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;az ad signed-in-user show &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; tsv&lt;span class="si"&gt;)&lt;/span&gt;

az cosmosdb sql role assignment create &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--account-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$COSMOS_ACCOUNT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--resource-group&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$RG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--role-definition-id&lt;/span&gt; &lt;span class="s2"&gt;"00000000-0000-0000-0000-000000000002"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--principal-id&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$USER_PRINCIPAL_ID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--scope&lt;/span&gt; &lt;span class="s2"&gt;"/"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then install the sample app's dependencies and run the seed script (it reads &lt;code&gt;COSMOS_ACCOUNT&lt;/code&gt;, &lt;code&gt;COSMOS_DB&lt;/code&gt;, and &lt;code&gt;COSMOS_CONTAINER&lt;/code&gt; from the environment):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cd &lt;/span&gt;sample-app
python3 &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate

pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
python insert_sample_data.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should now have 100 product documents in the container, each with name and description fields.&lt;/p&gt;

&lt;h3&gt;
  
  
  Grant OmniVec access to Azure Cosmos DB
&lt;/h3&gt;

&lt;p&gt;OmniVec pods authenticate to Azure Cosmos DB using a managed identity, not a connection string. Before you create a source or destination, grant that identity two roles on the Azure Cosmos DB account:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Data plane (&lt;code&gt;Cosmos DB Built-in Data Contributor&lt;/code&gt;):&lt;/strong&gt; read source documents and write embeddings.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Control plane (&lt;code&gt;Cosmos DB Account Reader Role&lt;/code&gt;):&lt;/strong&gt; read the account-level metadata and vector policies that the change-feed processor inspects at startup. Skipping it causes pipeline failures with a &lt;code&gt;readMetadata&lt;/code&gt; error.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;First, find the principal ID of the OmniVec workload identity. It lives in the OmniVec deployment's resource group (not the Azure Cosmos DB account's &lt;code&gt;$RG&lt;/code&gt;). That resource group has several managed identities, so filter by the client ID that &lt;code&gt;azd&lt;/code&gt; exported rather than picking the first one:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OMNIVEC_RG&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;azd &lt;span class="nb"&gt;env &lt;/span&gt;get-value AZURE_RESOURCE_GROUP&lt;span class="si"&gt;)&lt;/span&gt;

&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;OMNIVEC_PRINCIPAL_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;az identity list &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OMNIVEC_RG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="s2"&gt;"[?clientId=='&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;azd &lt;span class="nb"&gt;env &lt;/span&gt;get-value AZURE_IDENTITY_CLIENT_ID&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;'].principalId"&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; tsv&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Grant the data-plane role:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;az cosmosdb sql role assignment create &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--account-name&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$COSMOS_ACCOUNT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--resource-group&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$RG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--role-definition-id&lt;/span&gt; &lt;span class="s2"&gt;"00000000-0000-0000-0000-000000000002"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--principal-id&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OMNIVEC_PRINCIPAL_ID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--scope&lt;/span&gt; &lt;span class="s2"&gt;"/"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Grant the control-plane role:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;az role assignment create &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--assignee&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$OMNIVEC_PRINCIPAL_ID&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--role&lt;/span&gt; &lt;span class="s2"&gt;"Cosmos DB Account Reader Role"&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--scope&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;az cosmosdb show &lt;span class="nt"&gt;-n&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$COSMOS_ACCOUNT&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;-g&lt;/span&gt; &lt;span class="s2"&gt;"&lt;/span&gt;&lt;span class="nv"&gt;$RG&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt; &lt;span class="nt"&gt;--query&lt;/span&gt; &lt;span class="nb"&gt;id&lt;/span&gt; &lt;span class="nt"&gt;-o&lt;/span&gt; tsv&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Wait 1–2 minutes for the assignments to propagate before moving on.&lt;/p&gt;

&lt;h3&gt;
  
  
  Wire up the pipeline
&lt;/h3&gt;

&lt;p&gt;With Azure Cosmos DB ready and OmniVec authorized, the rest of the setup is three OmniVec resources: a source, a destination, and a pipeline that binds them to the model you registered earlier.&lt;/p&gt;

&lt;p&gt;Register the Azure Cosmos DB container as a source. OmniVec will watch its change feed:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;omnivec &lt;span class="nb"&gt;source &lt;/span&gt;create &lt;span class="nt"&gt;--name&lt;/span&gt; demo-cosmosdb-source &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--type&lt;/span&gt; cosmosdb &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--config&lt;/span&gt; &lt;span class="s2"&gt;"{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;endpoint&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;https://&lt;/span&gt;&lt;span class="nv"&gt;$COSMOS_ACCOUNT&lt;/span&gt;&lt;span class="s2"&gt;.documents.azure.com:443/&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;database&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="nv"&gt;$COSMOS_DB&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;container&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="nv"&gt;$COSMOS_CONTAINER&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;auth_type&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;managed-identity&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Register the same Azure Cosmos DB container as a destination. OmniVec will write embeddings back into it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;omnivec destination create &lt;span class="nt"&gt;--name&lt;/span&gt; demo-cosmosdb-destination &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--type&lt;/span&gt; cosmosdb-vector &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--config&lt;/span&gt; &lt;span class="s2"&gt;"{&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;endpoint&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;https://&lt;/span&gt;&lt;span class="nv"&gt;$COSMOS_ACCOUNT&lt;/span&gt;&lt;span class="s2"&gt;.documents.azure.com:443/&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;database&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="nv"&gt;$COSMOS_DB&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;container&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="nv"&gt;$COSMOS_CONTAINER&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;,&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;auth_type&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;managed-identity&lt;/span&gt;&lt;span class="se"&gt;\"&lt;/span&gt;&lt;span class="s2"&gt;}"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The pipeline needs three IDs: source, destination, and model. Grab the source and destination IDs from &lt;code&gt;omnivec source list&lt;/code&gt; and &lt;code&gt;omnivec destination list&lt;/code&gt; (they look like &lt;code&gt;src-…&lt;/code&gt; and &lt;code&gt;dst-…&lt;/code&gt;). For the model, the registered name (demo-foundry-oai-model) isn't the ID; the internal &lt;code&gt;mdl-ext-*&lt;/code&gt; ID is what the pipeline expects:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;SOURCE_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;src-id-from-source-list&amp;gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;DESTINATION_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;dst-id-from-destination-list&amp;gt;
&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;MODEL_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;omnivec model &lt;span class="nb"&gt;test &lt;/span&gt;demo-foundry-oai-model | &lt;span class="nb"&gt;sed&lt;/span&gt; &lt;span class="s1"&gt;'s/^OK: Model test returned: //'&lt;/span&gt; | jq &lt;span class="nt"&gt;-r&lt;/span&gt; &lt;span class="s1"&gt;'.id'&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Create the pipeline. &lt;code&gt;--content-fields&lt;/code&gt; tells OmniVec which fields on each source document to embed (concatenated), &lt;code&gt;--embedding-field&lt;/code&gt; is where the resulting vector lands on the destination document, and &lt;code&gt;--vector-index-path&lt;/code&gt; is the path the destination container's vector index looks at (it should match the path you set in the &lt;code&gt;az cosmosdb sql container create&lt;/code&gt; step):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;omnivec pipeline create &lt;span class="nt"&gt;--name&lt;/span&gt; demo-cosmosdb-pipeline &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--source&lt;/span&gt; &lt;span class="nv"&gt;$SOURCE_ID&lt;/span&gt; &lt;span class="nt"&gt;--destination&lt;/span&gt; &lt;span class="nv"&gt;$DESTINATION_ID&lt;/span&gt; &lt;span class="nt"&gt;--model&lt;/span&gt; &lt;span class="nv"&gt;$MODEL_ID&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--content-fields&lt;/span&gt; name,description &lt;span class="nt"&gt;--embedding-field&lt;/span&gt; embedding &lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="nt"&gt;--vector-index-path&lt;/span&gt; /embedding &lt;span class="nt"&gt;--processing-mode&lt;/span&gt; inline
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You should see something like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;OK: Pipeline created: pip-94348d5e (status: paused)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;New pipelines start paused. Grab the pipeline ID from the output (or from &lt;code&gt;omnivec pipeline list&lt;/code&gt;) and resume it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;export &lt;/span&gt;&lt;span class="nv"&gt;PIPELINE_ID&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&amp;lt;pip-id-from-create-output&amp;gt;
omnivec pipeline resume &lt;span class="nv"&gt;$PIPELINE_ID&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Check the pipeline's progress:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;omnivec pipeline show &lt;span class="nv"&gt;$PIPELINE_ID&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once the workers have processed the seed data, you'll see output similar to the following (truncated for brevity):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Pipeline
ID: pip-94348d5e
Name: demo-cosmosdb-pipeline
Status: active
...

Stats
Documents Embedded: 100
Source Docs: 100
Completion: 100.0%
Failed: 0
Pending: 0
...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Completion: 100.0% means every seed document now has an embedding written back to its embedding field. From this point on, any insert or update to the source container flows through the change feed and gets re-embedded automatically.&lt;/p&gt;

&lt;h3&gt;
  
  
  Run vector search
&lt;/h3&gt;

&lt;p&gt;The embeddings are in place, so you can run vector search against the destination. Use the OmniVec CLI's search command with a natural-language query:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;omnivec search &lt;span class="s2"&gt;"warm waterproof hiking pants"&lt;/span&gt; &lt;span class="nt"&gt;--index&lt;/span&gt; &lt;span class="nv"&gt;$DESTINATION_ID&lt;/span&gt; &lt;span class="nt"&gt;--top-k&lt;/span&gt; 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try another query to confirm it generalizes beyond the obvious matches:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;omnivec search &lt;span class="s2"&gt;"lightweight running shoes"&lt;/span&gt; &lt;span class="nt"&gt;--index&lt;/span&gt; &lt;span class="nv"&gt;$DESTINATION_ID&lt;/span&gt; &lt;span class="nt"&gt;--top-k&lt;/span&gt; 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The web UI ships with a vector search playground that calls the same API.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdp2rndb86n9o4pwlfyo9.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Farticles%2Fdp2rndb86n9o4pwlfyo9.png" alt=" " width="800" height="546"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Wrapping up
&lt;/h2&gt;

&lt;p&gt;The walkthrough above used Azure Cosmos DB as both source and destination, with a hosted Azure OpenAI embedding model, but you can mix and match sources, destinations, and models. It supports a wide range of scenarios – a common use case is pointing OmniVec at an Azure Blob Storage container full of PDFs and other documents and writing the embeddings into Azure Cosmos DB.&lt;/p&gt;

&lt;p&gt;OmniVec is on GitHub at &lt;a href="https://github.com/AzureCosmosDB/OmniVec" rel="noopener noreferrer"&gt;AzureCosmosDB/OmniVec&lt;/a&gt;. It is a public preview, so expect changes as it matures. Clone it, deploy it into your own subscription, and try it on one of your own datasets. Bug reports, feedback, and requests are all welcome through GitHub issues. And if you build something interesting on top of it, we'd love to hear about that too!&lt;/p&gt;

</description>
      <category>ai</category>
      <category>openai</category>
      <category>vectordatabase</category>
      <category>azure</category>
    </item>
    <item>
      <title>Announcing the Public Preview of Integrated Embeddings in Azure Cosmos DB: Build AI Apps With Embeddings That Stay in Sync</title>
      <dc:creator>Abhishek Gupta</dc:creator>
      <pubDate>Tue, 23 Jun 2026 18:04:23 +0000</pubDate>
      <link>https://dev.to/abhirockzz/announcing-the-public-preview-of-integrated-embeddings-in-azure-cosmos-db-build-ai-apps-with-234k</link>
      <guid>https://dev.to/abhirockzz/announcing-the-public-preview-of-integrated-embeddings-in-azure-cosmos-db-build-ai-apps-with-234k</guid>
      <description>&lt;p&gt;&lt;em&gt;Originally posted on &lt;a href="https://devblogs.microsoft.com/cosmosdb/announcing-the-public-preview-of-integrated-embeddings-in-azure-cosmos-db-build-ai-apps-with-embeddings-that-stay-in-sync/" rel="noopener noreferrer"&gt;https://devblogs.microsoft.com/cosmosdb/announcing-the-public-preview-of-integrated-embeddings-in-azure-cosmos-db-build-ai-apps-with-embeddings-that-stay-in-sync/&lt;/a&gt;&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;AI applications built on Azure Cosmos DB depend on embeddings for grounded results. Keeping them in sync with your data is the hard part: it means building and operating a separate data pipeline to track changes, call an embedding model, and write the results back to Azure Cosmos DB. In practice, that pipeline also has to handle failures and retries, throttling, scaling, and monitoring as your data and traffic grow.&lt;/p&gt;

&lt;p&gt;Integrated Embeddings in Azure Cosmos DB, now in Public Preview, removes that heavy lifting. Azure Cosmos DB automatically generates and maintains the embeddings for you as items are written and updated, so the vectors stored alongside your items always reflect the current state of your data. You configure it by specifying the source properties to embed, the Microsoft Foundry embedding model to use, and the path where the generated embeddings are stored, and then focus on building AI applications, such as Retrieval-Augmented Generation (RAG), on top of your data.&lt;/p&gt;

&lt;p&gt;  &lt;iframe src="https://www.youtube.com/embed/obYZG0hulHw"&gt;
  &lt;/iframe&gt;
&lt;/p&gt;

&lt;h2&gt;
  
  
  How Integrated Embeddings works
&lt;/h2&gt;

&lt;p&gt;Integrated Embeddings is configured through a new &lt;code&gt;embeddingSource&lt;/code&gt; block in the &lt;a href="https://learn.microsoft.com/azure/cosmos-db/vector-search#container-vector-policies" rel="noopener noreferrer"&gt;container vector policy&lt;/a&gt;. The rest of the policy (vector path, dimensions, distance function) stays the same. This block tells Azure Cosmos DB three things:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;What to embed:&lt;/strong&gt; one or more item properties listed in &lt;code&gt;sourcePaths&lt;/code&gt;. When you list multiple paths, the values are combined into a single input for the embedding model. An item is re-embedded only when one of these properties changes.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;What to embed with:&lt;/strong&gt; a Microsoft Foundry embedding model deployment, identified by &lt;code&gt;deploymentName&lt;/code&gt;, &lt;code&gt;modelName&lt;/code&gt;, and &lt;code&gt;endpoint&lt;/code&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;How to authenticate:&lt;/strong&gt; &lt;code&gt;authType&lt;/code&gt;: &lt;code&gt;"Entra"&lt;/code&gt; — currently the only supported value.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, here is a vector policy that embeds the &lt;code&gt;/text&lt;/code&gt; property of each item using &lt;code&gt;text-embedding-3-small&lt;/code&gt; and writes the resulting vector to &lt;code&gt;/embedding&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"vectorEmbeddings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/embedding"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"dataType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"float32"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"dimensions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1536&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"distanceFunction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cosine"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"embeddingSource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"sourcePaths"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s2"&gt;"/text"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"deploymentName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text-embedding-3-small"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"modelName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text-embedding-3-small"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"endpoint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://&amp;lt;foundry-resource-name&amp;gt;.openai.azure.com/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"authType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Entra"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At the time of Public Preview, the following Azure OpenAI embedding models are supported through Microsoft Foundry: &lt;code&gt;text-embedding-3-small&lt;/code&gt;, &lt;code&gt;text-embedding-3-large&lt;/code&gt;, and &lt;code&gt;text-embedding-ada-002&lt;/code&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Integrated Embeddings in action
&lt;/h2&gt;

&lt;p&gt;To get started with a simple example, try the &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/integrated-embeddings?tabs=python#get-started-with-integrated-embeddings" rel="noopener noreferrer"&gt;quickstart in the docs&lt;/a&gt;. It walks through creating a container with an &lt;code&gt;embeddingSource&lt;/code&gt; policy, inserting a few sample items, and verifying that Azure Cosmos DB writes an embedding to each item.&lt;/p&gt;

&lt;p&gt;The walkthrough below is a longer, end-to-end example. You'll load a dataset of outdoor products into Azure Cosmos DB, let Integrated Embeddings generate the vectors, and then run a vector search against the container.&lt;/p&gt;

&lt;p&gt;Before you start, complete the &lt;a href="https://learn.microsoft.com/azure/cosmos-db/integrated-embeddings#prerequisites" rel="noopener noreferrer"&gt;Integrated Embeddings prerequisites&lt;/a&gt; from the documentation: vector search, change feed mode enabled, and a Microsoft Foundry model deployment. The Azure Cosmos DB account's managed identity also needs the &lt;code&gt;Cognitive Services OpenAI User&lt;/code&gt; role on the Microsoft Foundry resource so it can call the model.&lt;/p&gt;

&lt;p&gt;In addition, the principal you sign in as needs two role assignments on the Azure Cosmos DB account so the sample app can act on your behalf:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;Cosmos DB Operator&lt;/code&gt; (Azure RBAC) to create the database and container through Azure Resource Manager.&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;Cosmos DB Built-in Data Contributor&lt;/code&gt; (Azure Cosmos DB RBAC) to upsert and read items. See &lt;a href="https://learn.microsoft.com/azure/cosmos-db/integrated-embeddings?tabs=python#use-the-azure-management-sdk-with-microsoft-entra-id" rel="noopener noreferrer"&gt;how to assign these roles&lt;/a&gt; in the getting started section.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In step 4 the sample app calls the Microsoft Foundry embedding deployment directly to embed the query string. For simplicity, the sample uses an API key for this call (Integrated Embeddings itself uses Entra ID, as configured in the vector policy). &lt;a href="https://learn.microsoft.com/azure/foundry/openai/tutorials/embeddings?tabs=command-line#retrieve-key-and-endpoint" rel="noopener noreferrer"&gt;Make sure you have the API key&lt;/a&gt; for your Foundry resource ahead of time and have it ready to drop into &lt;code&gt;.env&lt;/code&gt; file.&lt;/p&gt;

&lt;h3&gt;
  
  
  Set up the sample application
&lt;/h3&gt;

&lt;p&gt;The sample app is written in Python; you'll need Python 3.x installed locally. Clone the GitHub repository and install dependencies:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/abhirockzz/integrated-embeddings-sample
&lt;span class="nb"&gt;cd &lt;/span&gt;integrated-embeddings-sample

&lt;span class="c"&gt;# create a virtual environment and install dependencies&lt;/span&gt;
python &lt;span class="nt"&gt;-m&lt;/span&gt; venv .venv &lt;span class="o"&gt;&amp;amp;&amp;amp;&lt;/span&gt; &lt;span class="nb"&gt;source&lt;/span&gt; .venv/bin/activate
pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Copy &lt;code&gt;.env.example&lt;/code&gt; to &lt;code&gt;.env&lt;/code&gt; and fill in your Azure Cosmos DB account endpoint and Microsoft Foundry deployment details:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;&lt;span class="nb"&gt;cp&lt;/span&gt; .env.example .env
&lt;span class="c"&gt;# edit .env&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Sign in to the Azure CLI so the sample app can authenticate to Azure Cosmos DB and Microsoft Foundry using your identity:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;az login
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 1: Create the database and container
&lt;/h3&gt;

&lt;p&gt;This script creates the database and a container along with a vector embedding policy that has an &lt;code&gt;embeddingSource&lt;/code&gt; block with source path &lt;code&gt;/description&lt;/code&gt;, model &lt;code&gt;text-embedding-3-small&lt;/code&gt;, and output stored at &lt;code&gt;/embedding&lt;/code&gt;. It adds a &lt;code&gt;quantizedFlat&lt;/code&gt; vector index on &lt;code&gt;/embedding&lt;/code&gt; so you can query the embeddings in step 4.&lt;/p&gt;

&lt;p&gt;Run the script:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python create_db_and_container.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The container is provisioned with autoscale 1,000 RU/s.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Insert sample data
&lt;/h3&gt;

&lt;p&gt;This script upserts 100 outdoor-product items from items.json into the container. Each item has an &lt;code&gt;id&lt;/code&gt;, a &lt;code&gt;name&lt;/code&gt;, a &lt;code&gt;description&lt;/code&gt;, a &lt;code&gt;category&lt;/code&gt;, &lt;code&gt;tags&lt;/code&gt;, and a few other fields — but only &lt;code&gt;/description&lt;/code&gt; is sent to the embedding model, per the policy you set in step 1.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python insert_sample_data.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You'll see one line per item as it's inserted. None of the items have an embedding field yet; Azure Cosmos DB picks up the changes and generates embeddings asynchronously.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Verify embeddings in the Azure portal
&lt;/h3&gt;

&lt;p&gt;Open the &lt;a href="https://portal.azure.com/" rel="noopener noreferrer"&gt;Azure portal&lt;/a&gt;, navigate to your Azure Cosmos DB account → Data Explorer, open the container you created in step 1, and run the query below.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight sql"&gt;&lt;code&gt;&lt;span class="k"&gt;SELECT&lt;/span&gt; &lt;span class="n"&gt;VALUE&lt;/span&gt; &lt;span class="k"&gt;COUNT&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;FROM&lt;/span&gt; &lt;span class="k"&gt;c&lt;/span&gt; &lt;span class="k"&gt;WHERE&lt;/span&gt; &lt;span class="n"&gt;IS_DEFINED&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;c&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;embedding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When the count reaches 100, all embeddings have been generated.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Run a vector search
&lt;/h3&gt;

&lt;p&gt;Now that every item has an embedding, you can run a vector search against the container. The script embeds your query string by calling the same Microsoft Foundry embedding model deployment that Azure Cosmos DB used for the items (using the &lt;code&gt;FOUNDRY_API_KEY&lt;/code&gt; you set in &lt;code&gt;.env&lt;/code&gt; file), then runs a &lt;code&gt;VectorDistance()&lt;/code&gt; query to find the closest items by cosine similarity.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python vector_search.py &lt;span class="s2"&gt;"I need to stay warm on a cold ski trip"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Running this returns something similar to the following results. You should see a mix of ski-related gloves and jackets along with some cold-weather sleeping bags — all relevant to the concept of "staying warm on a cold ski trip," even though none of the item descriptions contain those exact words.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;Query: 'I need to stay warm on a cold ski trip'
Top 5 results:

1. Studio Talon Insulated Storm Glove
category=Winter Sports, Gloves, Insulated Gloves score=0.4974
2. Prairie Nomad Waterproof Resort Shell Jacket
category=Skiing, Outerwear, Shell Jackets score=0.4923
3. Ridge Drift Touchscreen Insulated Ski Glove
category=Winter Sports, Gloves, Insulated Gloves score=0.4855
4. Everest All-Weather Short 850 Fill Trail Sack
category=Camping, Sleeping Bags, Down Bags score=0.4756
5. Brook Shift 850-Fill Trail Sack Sleeping Bag
category=Camping, Sleeping Bags, Down Bags score=0.4570
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A couple more queries to give you a feel for what's possible.&lt;/p&gt;

&lt;p&gt;Try a planning-style query. Instead of gear, you'll get trip-planning books and trail guides:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python vector_search.py &lt;span class="s2"&gt;"plan a long hike in unfamiliar terrain"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Or try a more specific query. The top result is a one-person shelter, with closely related tents below it:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python vector_search.py &lt;span class="s2"&gt;"easy to set up shelter for one person"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can use &lt;code&gt;--top-k&lt;/code&gt; to control how many results are returned (defaults to 5):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python vector_search.py &lt;span class="s2"&gt;"lightweight cookware for backpacking"&lt;/span&gt; &lt;span class="nt"&gt;--top-k&lt;/span&gt; 3
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Pure vector search returns the most semantically similar items but doesn't account for exact keyword matches. For queries where both semantic intent and specific terms matter, &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/gen-ai/hybrid-search" rel="noopener noreferrer"&gt;Azure Cosmos DB for NoSQL supports hybrid search&lt;/a&gt;, which combines vector similarity and full-text (BM25) ranking using Reciprocal Rank Fusion. You can also add a &lt;code&gt;WHERE&lt;/code&gt; clause to narrow results to a specific category or tag. All of these queries run against the same embeddings that Integrated Embeddings generates and keeps in sync.&lt;/p&gt;

&lt;h2&gt;
  
  
  Build a simple RAG agent on top of the data
&lt;/h2&gt;

&lt;p&gt;Retrieval-Augmented Generation (RAG) is a pattern where a language model answers user questions by first retrieving relevant content from a knowledge base, then using that content as grounding for its response. For RAG over your Azure Cosmos DB data, the retrieval step is vector search and the knowledge base is your container.&lt;/p&gt;

&lt;p&gt;To turn the vector search into a Retrieval-Augmented Generation (RAG) application, we wrap it as a tool that a language model can call. We use a simple &lt;a href="https://docs.langchain.com/oss/python/langchain/rag" rel="noopener noreferrer"&gt;LangChain&lt;/a&gt; agent with a &lt;code&gt;retrieve_context&lt;/code&gt; tool that embeds the user's query and runs the same &lt;code&gt;VectorDistance()&lt;/code&gt; search you saw in step 4. The agent decides when to call the tool, reads the results, and answers in natural language. To keep the agent grounded in your data, the system prompt instructs the model to recommend only products that appear in the retrieved results and to ignore any instructions contained in the retrieved text.&lt;/p&gt;

&lt;p&gt;The agent needs a large language model (LLM). &lt;a href="https://learn.microsoft.com/azure/foundry/foundry-models/how-to/deploy-foundry-models#deploy-a-model" rel="noopener noreferrer"&gt;Deploy the model&lt;/a&gt; (for example &lt;code&gt;gpt-5.4&lt;/code&gt;) in your Microsoft Foundry resource and set &lt;code&gt;FOUNDRY_CHAT_DEPLOYMENT&lt;/code&gt; in &lt;code&gt;.env&lt;/code&gt; to the deployment name. The agent uses the same &lt;code&gt;FOUNDRY_API_KEY&lt;/code&gt; for both chat and query-time embedding calls.&lt;/p&gt;

&lt;p&gt;Once you start the agent, it opens a simple interactive prompt where you can ask catalog-style questions:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;python rag_agent.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Try out a few queries. For example, ask about a product category and the agent surfaces every relevant item:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: What sleeping bags do you have for cold nights?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The agent calls the retrieval tool, gets back the three cold-weather down bags in the catalog, and lists them with their shared 850-fill warmth and use cases.&lt;/p&gt;

&lt;p&gt;Ask about a specific product feature and the agent filters the results for you:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;You: What ski goggles do you have with a magnetic lens?
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Vector search returns all three ski goggles in the catalog, but the agent recommends only the two that actually have a magnetic lens system. This is the agent + RAG advantage on top of pure vector search: broad retrieval, narrow reasoning.&lt;/p&gt;

&lt;p&gt;Integrated Embeddings keeps the item embeddings in sync with the source data automatically, so the agent's retrieval stays accurate as products are added, updated, or removed. You don't have to build or run a separate embedding pipeline to keep the index fresh.&lt;/p&gt;

&lt;h2&gt;
  
  
  Other ways to configure Integrated Embeddings
&lt;/h2&gt;

&lt;p&gt;You can embed more than one property at a time by listing multiple paths in &lt;code&gt;sourcePaths&lt;/code&gt;. Azure Cosmos DB concatenates the values into a single input for the embedding model. This is useful when no single field carries enough information. For example, a product title is usually too short on its own, but combining &lt;code&gt;/title&lt;/code&gt; and &lt;code&gt;/description&lt;/code&gt; produces a richer vector.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"vectorEmbeddings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/embedding"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"dataType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"float32"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"dimensions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1536&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"distanceFunction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cosine"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"embeddingSource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"sourcePaths"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="s2"&gt;"/title"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="s2"&gt;"/description"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"deploymentName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text-embedding-3-small"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"modelName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text-embedding-3-small"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"endpoint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://&amp;lt;foundry-resource-name&amp;gt;.openai.azure.com/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"authType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Entra"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can also generate multiple embeddings by adding more entries to &lt;code&gt;vectorEmbeddings&lt;/code&gt;. Each entry has its own path, model, and source properties, and Azure Cosmos DB maintains all of the vectors in parallel.&lt;/p&gt;

&lt;p&gt;The example below generates &lt;code&gt;/desc_embedding&lt;/code&gt; from &lt;code&gt;/description&lt;/code&gt; using &lt;code&gt;text-embedding-3-large&lt;/code&gt;, and &lt;code&gt;/title_embedding&lt;/code&gt; from &lt;code&gt;/title&lt;/code&gt; using &lt;code&gt;text-embedding-3-small&lt;/code&gt;.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight json"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="nl"&gt;"vectorEmbeddings"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/desc_embedding"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"dataType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"float32"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"dimensions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3072&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"distanceFunction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cosine"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"embeddingSource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"sourcePaths"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="s2"&gt;"/description"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"deploymentName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text-embedding-3-large"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"modelName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text-embedding-3-large"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"endpoint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://&amp;lt;foundry-resource-name&amp;gt;.openai.azure.com/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"authType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Entra"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"path"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"/title_embedding"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"dataType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"float32"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"dimensions"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1536&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"distanceFunction"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"cosine"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="nl"&gt;"embeddingSource"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"sourcePaths"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt;
          &lt;/span&gt;&lt;span class="s2"&gt;"/title"&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"deploymentName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text-embedding-3-small"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"modelName"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"text-embedding-3-small"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"endpoint"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"https://&amp;lt;foundry-resource-name&amp;gt;.openai.azure.com/"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt;
        &lt;/span&gt;&lt;span class="nl"&gt;"authType"&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;"Entra"&lt;/span&gt;&lt;span class="w"&gt;
      &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
  &lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt;
&lt;/span&gt;&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  What's supported in Public Preview
&lt;/h2&gt;

&lt;p&gt;You can configure Integrated Embeddings today through the Azure Cosmos DB SDK (for Python) with key-based authentication, or through the Azure Cosmos DB management SDK (Python and JavaScript) with Microsoft Entra ID. Both options are demonstrated in the &lt;a href="https://learn.microsoft.com/azure/cosmos-db/integrated-embeddings?tabs=python#get-started-with-integrated-embeddings" rel="noopener noreferrer"&gt;documentation&lt;/a&gt;. Support across the Azure CLI, ARM, Bicep, and other SDKs will be added in subsequent releases.&lt;/p&gt;

&lt;p&gt;Azure Portal support for configuring and managing Integrated Embeddings (in Data Explorer) is not available yet. As we work on adding this, you can configure Integrated Embeddings through one of the SDK options.&lt;/p&gt;

&lt;h2&gt;
  
  
  Get started
&lt;/h2&gt;

&lt;p&gt;With Integrated Embeddings, Azure Cosmos DB keeps vector embeddings in sync with your data automatically, so you no longer need to build and operate separate pipelines to do it. Integrated Embeddings uses your existing Microsoft Foundry and Azure Cosmos DB resources, so the only costs are the Foundry inference calls and the request units used to read the change feed and write embeddings back to your items.&lt;/p&gt;

&lt;p&gt;To start building:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Follow the &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/integrated-embeddings?tabs=python#get-started-with-integrated-embeddings" rel="noopener noreferrer"&gt;quickstart&lt;/a&gt; to create a container with an &lt;code&gt;embeddingSource&lt;/code&gt; policy and insert your first items.&lt;/li&gt;
&lt;li&gt;Clone the &lt;a href="https://github.com/abhirockzz/integrated-embeddings-sample" rel="noopener noreferrer"&gt;sample app&lt;/a&gt; to run the full walkthrough above on your own data.&lt;/li&gt;
&lt;li&gt;Read the &lt;a href="https://aka.ms/integrated-embeddings-doc" rel="noopener noreferrer"&gt;Integrated Embeddings documentation&lt;/a&gt; for the complete reference.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;We'd love your feedback during preview! Reach out to us at &lt;a href="mailto:CosmosSearch@Microsoft.com"&gt;CosmosSearch@Microsoft.com&lt;/a&gt;.&lt;/p&gt;

</description>
      <category>python</category>
      <category>ai</category>
      <category>azure</category>
      <category>nosql</category>
    </item>
    <item>
      <title>A Chrome Extension That Talks to Your Database</title>
      <dc:creator>Abhishek Gupta</dc:creator>
      <pubDate>Mon, 23 Mar 2026 06:55:35 +0000</pubDate>
      <link>https://dev.to/abhirockzz/a-chrome-extension-that-talks-to-your-database-b7m</link>
      <guid>https://dev.to/abhirockzz/a-chrome-extension-that-talks-to-your-database-b7m</guid>
      <description>&lt;p&gt;&lt;strong&gt;Cosmos DB Sidekick&lt;/strong&gt; is a Chrome extension built with the &lt;a href="https://github.com/github/copilot-sdk" rel="noopener noreferrer"&gt;GitHub Copilot SDK&lt;/a&gt; and the &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/nosql/sdk-nodejs" rel="noopener noreferrer"&gt;Azure Cosmos DB JavaScript SDK&lt;/a&gt;. The GitHub Copilot SDK lets you embed Copilot's AI capabilities directly into your apps — available for Go, Python, TypeScript, and .NET.&lt;/p&gt;

&lt;p&gt;It sits alongside the &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/emulator" rel="noopener noreferrer"&gt;Cosmos DB vNext emulator&lt;/a&gt; Data Explorer and lets you ask questions in plain English. It writes the queries, runs them, and shows results. No copy-pasting SQL, no switching between tabs.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can find the code on &lt;a href="https://github.com/abhirockzz/cosmos-db-sidekick" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Here is a demo of the app in action&lt;/strong&gt;:&lt;/p&gt;



&lt;h2&gt;
  
  
  What can you actually do with it?
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Use natural language to query data.&lt;/strong&gt; In response to something like &lt;em&gt;"Find all orders over $100 from the last month"&lt;/em&gt; — the extension figures out the schema, generates a SQL query, runs it against your emulator, and streams back the results.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Write data too.&lt;/strong&gt; Need test data? Ask it to &lt;em&gt;"Add 10 test users to the users container"&lt;/em&gt; and it generates realistic documents with proper &lt;code&gt;id&lt;/code&gt; fields and partition keys, then upserts them.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;It knows what you're looking at.&lt;/strong&gt; When the Cosmos DB Data Explorer is open, the extension auto-detects which database and container you're browsing. A context bar shows something like &lt;code&gt;📂 ordersDb › customers&lt;/code&gt;, and your questions automatically target that data. Switch to a different container in the Data Explorer — the context follows.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9u8unptf4e6oip4zaw10.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F9u8unptf4e6oip4zaw10.png" alt="Context-aware integration" width="800" height="448"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Conversations persist.&lt;/strong&gt; You can have multi-turn conversations, switch between sessions, and pick up where you left off. Close the side panel, reopen it — your chat history is still there.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftr28t2rt0aglsulbv2bk.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Ftr28t2rt0aglsulbv2bk.png" alt="Conversation management" width="800" height="932"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  How the Copilot SDK makes this work
&lt;/h2&gt;

&lt;p&gt;Under the hood, the extension is powered by the &lt;a href="https://github.com/github/copilot-sdk" rel="noopener noreferrer"&gt;GitHub Copilot SDK&lt;/a&gt;. The architecture is straightforward:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;┌─────────────────────┐
│  Chrome Extension   │
│    (side panel)     │
└────────┬────────────┘
         │ HTTP + SSE
┌────────▼────────────┐       ┌──────────────────────┐
│   Node.js Sidecar   │──────▶│  GitHub Copilot SDK  │
│                     │◀──────│  (LLM + tool calls)  │
└────────┬────────────┘       └──────────────────────┘
         │ Cosmos DB JS SDK
┌────────▼────────────┐
│  Cosmos DB vNext    │
│     Emulator        │
└─────────────────────┘
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The sidecar is a lightweight Node.js server that acts as the bridge. It creates a &lt;code&gt;CopilotClient&lt;/code&gt;, manages chat sessions, and, (most importantly) defines &lt;strong&gt;tools&lt;/strong&gt; that the LLM can call autonomously. Tools are the key to the agentic behavior — they let the model interact with the external world (in this case, your Cosmos DB instance) in a structured way:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;list_databases&lt;/code&gt; — discover what databases exist&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;list_containers&lt;/code&gt; — see containers and partition keys in a database
&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;sample_documents&lt;/code&gt; — grab sample docs to understand the schema&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;run_query&lt;/code&gt; — execute a read-only SQL query&lt;/li&gt;
&lt;li&gt;
&lt;code&gt;upsert_items&lt;/code&gt; — insert or replace documents&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;For example, what happens when you ask a question like &lt;em&gt;"What does the schema look like?"&lt;/em&gt;. You didn't tell it which database to query. You didn't tell it to sample documents. But the LLM chains the tools together on its own — lists databases, picks the one from your context, lists containers, samples documents, then describes what it found. That's the agentic part. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Same applies to query generation and execution - you define the tools, the SDK handles the orchestration, and the model decides the sequence.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Here's what a tool definition looks like (simplified):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="nl"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;run_query&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Execute a read-only SQL query against a Cosmos DB container.&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="nx"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;object&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="nx"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
      &lt;span class="nl"&gt;database&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;  &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The database name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The container name&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
      &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;     &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nl"&gt;type&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;string&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;The SQL query to execute&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="p"&gt;},&lt;/span&gt;
    &lt;span class="nx"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;database&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;container&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;query&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="nx"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;runQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;database&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;container&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;args&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The SDK takes care of the rest — passing tool definitions to the model, routing tool calls to your handlers, feeding results back into the conversation, and streaming the final response.&lt;/p&gt;

&lt;p&gt;Streaming is built into the session. The sidecar subscribes to session events and forwards them over SSE to the Chrome extension, so responses appear token-by-token in the chat panel. Creating a streaming chat session is a few lines:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createSession&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;model&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;gpt-4.1&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;systemMessage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;append&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;SYSTEM_PROMPT&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
  &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nf"&gt;getTools&lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
  &lt;span class="na"&gt;streaming&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;onPermissionRequest&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;approveAll&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Session persistence comes for free too. The SDK's &lt;code&gt;listSessions()&lt;/code&gt; and &lt;code&gt;resumeSession()&lt;/code&gt; let the extension show chat history and restore previous conversations — the sidecar doesn't need its own storage layer.&lt;/p&gt;

&lt;h2&gt;
  
  
  Context-aware — no configuration needed
&lt;/h2&gt;

&lt;p&gt;The extension watches which database and container you have open in the Data Explorer and automatically uses that as context. Ask &lt;em&gt;"show me the top 10 documents"&lt;/em&gt; and it knows exactly where to look — no need to specify the target every time.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it out
&lt;/h2&gt;

&lt;p&gt;The whole thing runs locally — Chrome extension + a Node.js sidecar + the &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/emulator" rel="noopener noreferrer"&gt;Cosmos DB vNext emulator&lt;/a&gt; in Docker. You'll need &lt;a href="https://docs.github.com/en/copilot" rel="noopener noreferrer"&gt;GitHub Copilot&lt;/a&gt; and the &lt;a href="https://docs.github.com/en/copilot/how-tos/set-up/install-copilot-cli" rel="noopener noreferrer"&gt;Copilot CLI&lt;/a&gt; set up for auth.&lt;/p&gt;

&lt;p&gt;Follow the &lt;a href="https://github.com/abhirockzz/cosmos-db-sidekick" rel="noopener noreferrer"&gt;steps in the GitHub repo&lt;/a&gt; to get it running, and start chatting with your database in natural language. It's a fun demo of how the GitHub Copilot SDK can turn a simple extension into an intelligent agent that understands your data and helps you interact with it seamlessly.&lt;/p&gt;

&lt;h2&gt;
  
  
  The bigger picture
&lt;/h2&gt;

&lt;p&gt;Cosmos DB Sidekick is one specific use case, but the pattern behind it is general. Define a few tools, hand them to the Copilot SDK, and you get an agent that can reason about when and how to use them — chaining calls, handling errors, and streaming results back to the user. The SDK handles sessions, tool orchestration, and model access; you just bring the domain logic.&lt;/p&gt;

&lt;p&gt;That same pattern works for any data source, any API, any workflow. A CLI that talks to your CI/CD pipeline. A Slack bot that queries your observability stack. A dashboard that lets non-technical teammates explore production metrics in plain English. The building blocks are the same: tools, a system prompt, and a session.&lt;/p&gt;

&lt;p&gt;If you're looking for a starting point, the &lt;a href="https://github.com/github/copilot-sdk" rel="noopener noreferrer"&gt;Copilot SDK&lt;/a&gt; has samples for Go, Python, TypeScript, and .NET. Pick your stack and start building.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>database</category>
      <category>agents</category>
    </item>
    <item>
      <title>DocumentDB on Kubernetes: Resilient, Highly Available Databases with Automatic Failover</title>
      <dc:creator>Abhishek Gupta</dc:creator>
      <pubDate>Tue, 03 Mar 2026 08:06:34 +0000</pubDate>
      <link>https://dev.to/abhirockzz/documentdb-on-kubernetes-resilient-highly-available-databases-with-automatic-failover-ak7</link>
      <guid>https://dev.to/abhirockzz/documentdb-on-kubernetes-resilient-highly-available-databases-with-automatic-failover-ak7</guid>
      <description>&lt;p&gt;&lt;a href="https://github.com/documentdb/documentdb" rel="noopener noreferrer"&gt;DocumentDB&lt;/a&gt; is an open-source MongoDB-compatible database built on PostgreSQL that provides a familiar interface while leveraging PostgreSQL's reliability and extensibility. The &lt;a href="https://github.com/documentdb/documentdb-kubernetes-operator" rel="noopener noreferrer"&gt;DocumentDB Kubernetes Operator&lt;/a&gt; brings this database to Kubernetes environments by extending the platform with custom resources. The operator manages DocumentDB clusters declaratively, handling deployment, scaling, upgrades, and high availability scenarios automatically.&lt;/p&gt;

&lt;p&gt;The DocumentDB Kubernetes Operator provides multiple levels of high availability, each addressing a different failure domain. &lt;strong&gt;Local HA&lt;/strong&gt; deploys multiple database instances within a single Kubernetes cluster with automatic failover in seconds, protecting against pod and node failures. For further resilience, you can configure &lt;strong&gt;availability zone spreading&lt;/strong&gt; so that replicas land in different AZs, allowing the cluster to survive a full zone outage without manual intervention. Beyond a single cluster, the operator supports &lt;strong&gt;multi-region HA&lt;/strong&gt; across Azure regions (using KubeFleet) and &lt;strong&gt;multi-cloud HA&lt;/strong&gt; across providers like Azure, AWS, and GCP (using Istio). Both use physical WAL replication with manual failover via &lt;code&gt;kubectl documentdb promote&lt;/code&gt;. These levels are composable: a production deployment can combine all of them.&lt;/p&gt;

&lt;p&gt;This post focuses on local HA, the foundational layer, and walks through automatic failover in action.&lt;/p&gt;

&lt;h2&gt;
  
  
  Highly Available DocumentDB deployment on Kubernetes
&lt;/h2&gt;

&lt;p&gt;In single-instance database deployments, any failure (such as a pod crash, node issue, or planned upgrade) may result in downtime. Local high availability (HA) solves this problem by deploying multiple database instances within a single Kubernetes cluster. The operator creates one primary instance that handles all client operations, along with multiple replica instances that are continuously replicated via asynchronous WAL streaming. When the primary fails, a replica is automatically promoted to become the new primary, ensuring your application experiences minimal disruption.&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq5826d4d46fq8rs5m0i4.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fq5826d4d46fq8rs5m0i4.png" alt="DocumentDB HA design" width="800" height="458"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Local HA is ideal when you need resilience within a single region without the complexity of multi-region deployments. It's a cost-effective solution for development and staging environments where you want to validate failover behavior without cloud distribution costs, as well as for production workloads that require automatic recovery from infrastructure failures. For cross-region disaster recovery scenarios, the operator also supports multi-cluster replication features.&lt;/p&gt;

&lt;h2&gt;
  
  
  Architecture Overview
&lt;/h2&gt;

&lt;p&gt;DocumentDB's local HA leverages CloudNativePG (CNPG) as its underlying PostgreSQL foundation. CNPG handles WAL-based streaming replication and automatic failover orchestration, while DocumentDB adds the MongoDB-compatible protocol layer on top.&lt;/p&gt;

&lt;p&gt;Here are the key components:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;CNPG Cluster&lt;/strong&gt;: Manages PostgreSQL replication (1 primary + N replicas) with WAL-based streaming&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;DocumentDB Gateway&lt;/strong&gt;: A sidecar container injected into each PostgreSQL pod that translates MongoDB wire protocol to PostgreSQL DocumentDB extension calls&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Kubernetes Services&lt;/strong&gt;: Layered service architecture for different access patterns:

&lt;ul&gt;
&lt;li&gt;Internal PostgreSQL services (port 5432): &lt;code&gt;&amp;lt;cluster&amp;gt;-rw&lt;/code&gt; (primary), &lt;code&gt;&amp;lt;cluster&amp;gt;-ro&lt;/code&gt; (replicas only), &lt;code&gt;&amp;lt;cluster&amp;gt;-r&lt;/code&gt; (all instances — primary and replicas) - used for internal operations, metrics, and backups&lt;/li&gt;
&lt;li&gt;External Gateway service (port 10260): Routes MongoDB client traffic to the current primary by tracking the &lt;code&gt;cnpg.io/instanceRole: primary&lt;/code&gt; label&lt;/li&gt;
&lt;/ul&gt;


&lt;/li&gt;

&lt;/ul&gt;

&lt;p&gt;When the primary fails, CNPG automatically detects the failure and promotes the most advanced replica to primary, updating the pod labels. The Kubernetes service automatically follows the new primary, keeping the external IP stable – no manual DNS changes required. The operator currently supports a &lt;strong&gt;maximum of 3 instances&lt;/strong&gt; (&lt;code&gt;instancesPerNode: 3&lt;/code&gt;), providing 1 primary + 2 replicas for optimal balance between availability, performance, and operational flexibility.&lt;/p&gt;

&lt;p&gt;Let's see how this works in practice.&lt;/p&gt;

&lt;h2&gt;
  
  
  Setting Up the Test Environment
&lt;/h2&gt;

&lt;p&gt;You need the following installed:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;code&gt;minikube&lt;/code&gt;, &lt;code&gt;kubectl&lt;/code&gt;, and &lt;code&gt;helm&lt;/code&gt;
&lt;/li&gt;
&lt;li&gt;Python (for the test client application)&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Start your &lt;code&gt;minikube&lt;/code&gt; cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;minikube start
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Also make sure to clone the GitHub repository:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;git clone https://github.com/abhirockzz/documentdb-local-ha-tutorial.git
&lt;span class="nb"&gt;cd &lt;/span&gt;documentdb-local-ha-tutorial
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Install DocumentDB Operator
&lt;/h3&gt;

&lt;p&gt;First, install &lt;code&gt;cert-manager&lt;/code&gt; (required dependency):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm repo add jetstack https://charts.jetstack.io
helm repo update

helm &lt;span class="nb"&gt;install &lt;/span&gt;cert-manager jetstack/cert-manager &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--namespace&lt;/span&gt; cert-manager &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--create-namespace&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--set&lt;/span&gt; &lt;span class="nv"&gt;installCRDs&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Install the DocumentDB operator:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;helm repo add documentdb https://documentdb.github.io/documentdb-kubernetes-operator

helm &lt;span class="nb"&gt;install &lt;/span&gt;documentdb-operator documentdb/documentdb-operator &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--namespace&lt;/span&gt; documentdb-operator &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--create-namespace&lt;/span&gt; &lt;span class="se"&gt;\&lt;/span&gt;
  &lt;span class="nt"&gt;--wait&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Verify the operator is running:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get deployment &lt;span class="nt"&gt;-n&lt;/span&gt; documentdb-operator
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;blockquote&gt;
&lt;p&gt;To check the operator version, run &lt;code&gt;kubectl get pods -n documentdb-operator -o jsonpath='{.items[*].spec.containers[*].image}' &amp;amp;&amp;amp; echo&lt;/code&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h3&gt;
  
  
  Deploy Local HA Cluster
&lt;/h3&gt;

&lt;p&gt;In a separate terminal, start the &lt;code&gt;minikube tunnel&lt;/code&gt;. This creates a network route that enables &lt;code&gt;LoadBalancer&lt;/code&gt; services to receive external IPs in your local &lt;code&gt;minikube&lt;/code&gt; environment. The tunnel will assign an IP address to the &lt;code&gt;DocumentDB&lt;/code&gt; service and route traffic from your host machine to the cluster, allowing the Python test client to connect:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;minikube tunnel

&lt;span class="c"&gt;# output:&lt;/span&gt;
✅  Tunnel successfully started

📌  NOTE: Please &lt;span class="k"&gt;do &lt;/span&gt;not close this terminal as this process must stay alive &lt;span class="k"&gt;for &lt;/span&gt;the tunnel to be accessible ...
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The &lt;a href="https://github.com/abhirockzz/documentdb-local-ha-tutorial/blob/main/local_ha.yaml" rel="noopener noreferrer"&gt;&lt;code&gt;local_ha.yaml&lt;/code&gt;&lt;/a&gt; file contains the complete configuration including namespace, credentials secret, and the DocumentDB resource with &lt;code&gt;instancesPerNode: 3&lt;/code&gt; to create a 3-instance HA cluster.&lt;/p&gt;

&lt;p&gt;Deploy the cluster:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl apply &lt;span class="nt"&gt;-f&lt;/span&gt; local_ha.yaml
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Monitor the pod status. Wait for all pods to be running (this may take 1-2 minutes). In the meantime, you should see output similar to this, and eventually all 3 pods will reach &lt;code&gt;Running&lt;/code&gt; status:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; documentdb-preview-ns &lt;span class="nt"&gt;-w&lt;/span&gt;

&lt;span class="c"&gt;# output:&lt;/span&gt;

NAME                                 READY   STATUS            RESTARTS   AGE
documentdb-local-ha-1-initdb-ffrjf   0/1     PodInitializing   0          3s
documentdb-local-ha-1-initdb-ffrjf   1/1     Running           0          24s
documentdb-local-ha-1-initdb-ffrjf   0/1     Completed         0          25s
documentdb-local-ha-1-initdb-ffrjf   0/1     Completed         0          27s
documentdb-local-ha-1-initdb-ffrjf   0/1     Completed         0          27s
documentdb-local-ha-1                0/2     Pending           0          0s
documentdb-local-ha-1                0/2     Pending           0          0s
//....
documentdb-local-ha-3                2/2     Running           0          11s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Go to the &lt;code&gt;minikube tunnel&lt;/code&gt; terminal, and verify the tunnel is now active for the DocumentDB service:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;Starting tunnel &lt;span class="k"&gt;for &lt;/span&gt;service documentdb-service-documentdb-local-ha.
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;You can verify the external IP assigned to the service (should be &lt;code&gt;127.0.0.1&lt;/code&gt; in this case):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get svc &lt;span class="nt"&gt;-n&lt;/span&gt; documentdb-preview-ns

&lt;span class="c"&gt;# output:&lt;/span&gt;
NAME                                     TYPE           CLUSTER-IP       EXTERNAL-IP   PORT&lt;span class="o"&gt;(&lt;/span&gt;S&lt;span class="o"&gt;)&lt;/span&gt;           AGE
documentdb-local-ha-r                    ClusterIP      10.108.176.232   &amp;lt;none&amp;gt;        5432/TCP          4m47s
documentdb-local-ha-ro                   ClusterIP      10.111.154.246   &amp;lt;none&amp;gt;        5432/TCP          4m47s
documentdb-local-ha-rw                   ClusterIP      10.101.235.95    &amp;lt;none&amp;gt;        5432/TCP          4m47s
documentdb-service-documentdb-local-ha   LoadBalancer   10.97.24.62      127.0.0.1     10260:31829/TCP   4m57s
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Ok now we are ready to test failover.&lt;/p&gt;

&lt;h2&gt;
  
  
  Test Failover
&lt;/h2&gt;

&lt;p&gt;The test uses a &lt;a href="https://github.com/abhirockzz/documentdb-local-ha-tutorial/blob/main/failover_test_read_write.py" rel="noopener noreferrer"&gt;Python client application&lt;/a&gt; that continuously performs write and read operations against the DocumentDB cluster. This includes retry logic with exponential backoff and tracks metrics like operation counts, failures, and downtime. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;Note that the client uses &lt;code&gt;retryWrites=True&lt;/code&gt;, which allows the MongoDB driver to automatically retry failed writes on the new primary — in very fast failovers, you may see zero reported failures as the driver absorbs the disruption transparently.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Start the client application:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;pip &lt;span class="nb"&gt;install&lt;/span&gt; &lt;span class="nt"&gt;-r&lt;/span&gt; requirements.txt
python failover_test_read_write.py
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let it run for ~15 seconds to establish a baseline. You'll see continuous write and read operations succeeding.&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;//....
[CLIENT][10:29:28.051] ✓ Connected to DocumentDB
[CLIENT][10:29:28.138] ✓ W#1 (44ms) | R#1 (43ms) | Avg W:44ms R:43ms | Docs: 1
[CLIENT][10:29:28.688] ✓ W#2 (2ms) | R#2 (43ms) | Avg W:23ms R:43ms | Docs: 2
[CLIENT][10:29:29.234] ✓ W#3 (2ms) | R#3 (43ms) | Avg W:16ms R:43ms | Docs: 3
[CLIENT][10:29:29.783] ✓ W#4 (3ms) | R#4 (43ms) | Avg W:13ms R:43ms | Docs: 4
[CLIENT][10:29:30.327] ✓ W#5 (2ms) | R#5 (42ms) | Avg W:11ms R:43ms | Docs: 5
//.....
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Trigger Failover
&lt;/h3&gt;

&lt;p&gt;In a new terminal, identify the current primary (the primary/replica roles may vary in your deployment):&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; documentdb-preview-ns &lt;span class="nt"&gt;-L&lt;/span&gt; cnpg.io/instanceRole

&lt;span class="c"&gt;# output:&lt;/span&gt;
NAME                    READY   STATUS    RESTARTS   AGE   INSTANCEROLE
documentdb-local-ha-1   2/2     Running   0          14m   primary
documentdb-local-ha-2   2/2     Running   0          14m   replica
documentdb-local-ha-3   2/2     Running   0          14m   replica
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Note which pod shows &lt;code&gt;primary&lt;/code&gt; role, then delete it to simulate a failure:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete pod &amp;lt;primary-pod-name&amp;gt; &lt;span class="nt"&gt;-n&lt;/span&gt; documentdb-preview-ns
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;So, in case your primary pod is &lt;code&gt;documentdb-local-ha-1&lt;/code&gt;, you would run: &lt;code&gt;kubectl delete pod documentdb-local-ha-1 -n documentdb-preview-ns&lt;/code&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  Automatic Recovery
&lt;/h3&gt;

&lt;p&gt;Watch the client terminal. You should see logs similar to this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[CLIENT][10:32:32.452] ✗ FAILOVER EVENT DETECTED
[CLIENT][10:32:32.452] ℹ   Error: the database system is shutting down, full error: {'ok': 0.0, 'code': 50463173, 'codeName': 'Error', 'errmsg': 'the database system is shutting down'}
[CLIENT][10:32:32.452] ℹ   Last successful write: #178
[CLIENT][10:32:32.452] ℹ ================================================================================
[CLIENT][10:32:32.500] ✗ ⚠ Write FAILED | ⚠ Read FAILED | Downtime: 0.0s | Failed W: 1 R: 1
[CLIENT][10:32:32.551] ↻ Attempting reconnection (backoff: 1.0s)...
[CLIENT][10:32:32.703] ✗ Connection failed: error connecting to server: Connection refused (os error 111), full error: {'ok': 0.0, 'code': 1, 'codeName': 'Internal Error', 'errmsg': 'error connecting to server: Connection refused (os error 111)'}
[CLIENT][10:32:33.705] ↻ Attempting reconnection (backoff: 2.0s)...
[CLIENT][10:32:33.947] ✓ Connected to DocumentDB
[CLIENT][10:32:33.947] ✓ Reconnection successful!
[CLIENT][10:32:33.998] ℹ ================================================================================
[CLIENT][10:32:33.998] ↻ RECOVERY COMPLETE
//.....
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Then the read and write operations should resume successfully:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;[CLIENT][10:32:34.044] ✓ W#179 (51ms) | R#179 (46ms) | Avg W:8ms R:39ms | Docs: 284
[CLIENT][10:32:34.593] ✓ W#180 (4ms) | R#180 (42ms) | Avg W:8ms R:39ms | Docs: 285
[CLIENT][10:32:35.143] ✓ W#181 (5ms) | R#181 (44ms) | Avg W:9ms R:39ms | Docs: 286
[CLIENT][10:32:35.693] ✓ W#182 (3ms) | R#182 (43ms) | Avg W:9ms R:39ms | Docs: 287
[CLIENT][10:32:36.238] ✓ W#183 (2ms) | R#183 (42ms) | Avg W:8ms R:39ms | Docs: 288
[CLIENT][10:32:36.787] ✓ W#184 (3ms) | R#184 (43ms) | Avg W:9ms R:39ms | Docs: 289
[CLIENT][10:32:37.333] ✓ W#185 (3ms) | R#185 (42ms) | Avg W:8ms R:39ms | Docs: 290
//....
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Let's take a closer look at what happened.&lt;/p&gt;

&lt;h3&gt;
  
  
  Behind the scenes
&lt;/h3&gt;

&lt;p&gt;These are the key events during failover:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Failure detection&lt;/strong&gt;: Operations start failing with connection errors&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;FAILOVER EVENT DETECTED&lt;/strong&gt;: The client recognizes the disruption&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Reconnection attempts&lt;/strong&gt;: Automatic retry with exponential backoff&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;RECOVERY COMPLETE&lt;/strong&gt;: Service automatically resumes&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb6b7573qdv92a4bmusmt.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fb6b7573qdv92a4bmusmt.png" alt=" " width="800" height="917"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Behind the scenes, CNPG automatically detects the primary pod termination, promotes a healthy replica to primary, and updates the &lt;code&gt;cnpg.io/instanceRole: primary&lt;/code&gt; label on the new primary pod. The Kubernetes service automatically routes traffic to the new primary (the external IP remains unchanged).&lt;/p&gt;

&lt;p&gt;The key to failover is the service's label selector mechanism. Since the service tracks pods with &lt;code&gt;cnpg.io/instanceRole: primary&lt;/code&gt;, when CNPG updates this label during promotion, the service endpoint automatically switches to the new primary without any DNS changes or client reconfiguration.&lt;/p&gt;

&lt;p&gt;Verify the new primary – you should see a different pod as the new primary (it may vary in your deployment). In this example, &lt;code&gt;documentdb-local-ha-3&lt;/code&gt; has become the new primary:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get pods &lt;span class="nt"&gt;-n&lt;/span&gt; documentdb-preview-ns &lt;span class="nt"&gt;-L&lt;/span&gt; cnpg.io/instanceRole

&lt;span class="c"&gt;# output:&lt;/span&gt;
NAME                    READY   STATUS    RESTARTS   AGE     INSTANCEROLE
documentdb-local-ha-1   2/2     Running   0          2m17s   replica
documentdb-local-ha-2   2/2     Running   0          18m     replica
documentdb-local-ha-3   2/2     Running   0          18m     primary
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Verify manually
&lt;/h3&gt;

&lt;p&gt;You can also connect directly using &lt;code&gt;mongosh&lt;/code&gt; to verify. First, get the connection string:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl get documentdb documentdb-local-ha &lt;span class="nt"&gt;-n&lt;/span&gt; documentdb-preview-ns

&lt;span class="c"&gt;# output:&lt;/span&gt;

NAME                  STATUS                     CONNECTION STRING
documentdb-local-ha   Cluster &lt;span class="k"&gt;in &lt;/span&gt;healthy state   mongodb://&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get secret documentdb-credentials &lt;span class="nt"&gt;-n&lt;/span&gt; documentdb-preview-ns &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.data.username}'&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;:&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get secret documentdb-credentials &lt;span class="nt"&gt;-n&lt;/span&gt; documentdb-preview-ns &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.data.password}'&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;@127.0.0.1:10260/?directConnection&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&amp;amp;authMechanism&lt;span class="o"&gt;=&lt;/span&gt;SCRAM-SHA-256&amp;amp;tls&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&amp;amp;tlsAllowInvalidCertificates&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&amp;amp;replicaSet&lt;span class="o"&gt;=&lt;/span&gt;rs0
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Use the connection string to connect with &lt;code&gt;mongosh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mongosh &lt;span class="s2"&gt;"mongodb://&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get secret documentdb-credentials &lt;span class="nt"&gt;-n&lt;/span&gt; documentdb-preview-ns &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.data.username}'&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;:&lt;/span&gt;&lt;span class="si"&gt;$(&lt;/span&gt;kubectl get secret documentdb-credentials &lt;span class="nt"&gt;-n&lt;/span&gt; documentdb-preview-ns &lt;span class="nt"&gt;-o&lt;/span&gt; &lt;span class="nv"&gt;jsonpath&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s1"&gt;'{.data.password}'&lt;/span&gt; | &lt;span class="nb"&gt;base64&lt;/span&gt; &lt;span class="nt"&gt;-d&lt;/span&gt;&lt;span class="si"&gt;)&lt;/span&gt;&lt;span class="s2"&gt;@127.0.0.1:10260/?directConnection=true&amp;amp;authMechanism=SCRAM-SHA-256&amp;amp;tls=true&amp;amp;tlsAllowInvalidCertificates=true&amp;amp;replicaSet=rs0"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Once connected, you can connect to the &lt;code&gt;testdb&lt;/code&gt; database and verify the documents:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="nx"&gt;rs0&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;direct&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mongos&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="nx"&gt;test&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;use&lt;/span&gt; &lt;span class="nx"&gt;testdb&lt;/span&gt;
&lt;span class="nx"&gt;switched&lt;/span&gt; &lt;span class="nx"&gt;to&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt; &lt;span class="nx"&gt;testdb&lt;/span&gt;
&lt;span class="nx"&gt;rs0&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;direct&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mongos&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="nx"&gt;testdb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;getCollectionNames&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="dl"&gt;'&lt;/span&gt;&lt;span class="s1"&gt;failover_test&lt;/span&gt;&lt;span class="dl"&gt;'&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="nx"&gt;rs0&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;direct&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mongos&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="nx"&gt;testdb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; &lt;span class="nx"&gt;db&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;failover_test&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;countDocuments&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="mi"&gt;408&lt;/span&gt;
&lt;span class="nx"&gt;rs0&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;direct&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;mongos&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt; &lt;span class="nx"&gt;testdb&lt;/span&gt;&lt;span class="o"&gt;&amp;gt;&lt;/span&gt; 
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Bonus exercise
&lt;/h3&gt;

&lt;p&gt;Try connecting to each cluster node directly. You can &lt;code&gt;kubectl port-forward&lt;/code&gt; to each pod. For example, to connect to &lt;code&gt;documentdb-local-ha-1&lt;/code&gt; over port &lt;code&gt;27017&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl port-forward &lt;span class="nt"&gt;-n&lt;/span&gt; documentdb-preview-ns documentdb-local-ha-1 27017:10260
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Now you can connect with &lt;code&gt;mongosh&lt;/code&gt;:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;mongosh &lt;span class="s2"&gt;"mongodb://k8s_secret_user:K8sSecret100@localhost:27017/?directConnection=true&amp;amp;authMechanism=SCRAM-SHA-256&amp;amp;tls=true&amp;amp;tlsAllowInvalidCertificates=true"&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Experiment with different commands and observe the behavior.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;You can also explore advanced scenarios like &lt;a href="https://github.com/documentdb/documentdb-kubernetes-operator/tree/main/documentdb-playground/aks-fleet-deployment" rel="noopener noreferrer"&gt;multi-region&lt;/a&gt; or &lt;a href="https://github.com/documentdb/documentdb-kubernetes-operator/tree/main/documentdb-playground/multi-cloud-deployment" rel="noopener noreferrer"&gt;multi-cloud&lt;/a&gt; deployments&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Cleanup
&lt;/h2&gt;

&lt;p&gt;To tear down the environment when you're done:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;kubectl delete namespace documentdb-preview-ns
helm uninstall documentdb-operator &lt;span class="nt"&gt;-n&lt;/span&gt; documentdb-operator
kubectl delete namespace documentdb-operator
minikube stop
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h2&gt;
  
  
  Wrapping Up
&lt;/h2&gt;

&lt;p&gt;The DocumentDB Kubernetes Operator provides local high availability with automatic failover capabilities. You have seen how the operator handles primary failures with minimal manual intervention, making it easier to build resilient database deployments on Kubernetes. &lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;This tutorial demonstrates basic failover recovery using a small dataset in a single-node cluster. In this case, the client-observed recovery time was approximately 1-3 seconds. Since CNPG uses asynchronous replication by default, note that transactions committed on the old primary but not yet replicated to standbys could be lost during an unplanned failover. Make sure to consider factors specific to your deployments for production or with larger datasets.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;Go ahead, try it out in your own environment, and let us know your feedback!&lt;/p&gt;

&lt;p&gt;Check out the &lt;a href="https://documentdb.github.io/documentdb-kubernetes-operator/" rel="noopener noreferrer"&gt;documentation&lt;/a&gt; for the latest feature updates. If you run into issues or have questions, reach out on &lt;a href="https://discordapp.com/channels/1374170121219866635/1435045191156236458" rel="noopener noreferrer"&gt;Discord&lt;/a&gt; or raise an issue on &lt;a href="https://github.com/documentdb/documentdb-kubernetes-operator/issues" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. Contributions are welcome, whether it's code, documentation improvements, or simply sharing your experience.&lt;/p&gt;

&lt;p&gt;Happy building!&lt;/p&gt;

</description>
      <category>kubernetes</category>
      <category>postgres</category>
      <category>python</category>
      <category>mongodb</category>
    </item>
    <item>
      <title>Build a Time Tracking App with GitHub Copilot SDK</title>
      <dc:creator>Abhishek Gupta</dc:creator>
      <pubDate>Mon, 02 Mar 2026 06:09:41 +0000</pubDate>
      <link>https://dev.to/abhirockzz/build-a-time-tracking-app-with-github-copilot-sdk-22b6</link>
      <guid>https://dev.to/abhirockzz/build-a-time-tracking-app-with-github-copilot-sdk-22b6</guid>
      <description>&lt;p&gt;The &lt;a href="https://github.com/github/copilot-sdk" rel="noopener noreferrer"&gt;GitHub Copilot SDK&lt;/a&gt; lets you embed Copilot's agentic workflows directly into your apps, and it's available for Python, TypeScript, Go, and .NET.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;TimeTrack&lt;/strong&gt; is a desktop app built with the GitHub Copilot SDK (TypeScript) and &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/introduction" rel="noopener noreferrer"&gt;Azure Cosmos DB&lt;/a&gt;. You can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;⏱️ Track time with a start/stop timer, projects, and tags&lt;/li&gt;
&lt;li&gt;🗣️ Ask questions about your time data in plain English — Copilot generates and runs Cosmos DB SQL queries behind the scenes&lt;/li&gt;
&lt;li&gt;📊 View reports and charts across multiple users&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;Here is a demo of the app in action&lt;/strong&gt;:&lt;/p&gt;



&lt;p&gt;If you want to try it yourself, the code is on &lt;a href="https://github.com/abhirockzz/cosmosdb-copilot-sdk-time-tracker" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. Works with Azure Cosmos DB or the vNext emulator — clone, configure, and &lt;code&gt;npm start&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;For local development, you don't need an Azure account. The &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/emulator-linux" rel="noopener noreferrer"&gt;Cosmos DB vNext emulator&lt;/a&gt; runs as a Docker container, so you can seed sample data and start querying right away.&lt;/p&gt;

&lt;h2&gt;
  
  
  Behind the Scenes
&lt;/h2&gt;

&lt;p&gt;What makes this interesting is the SDK's tool calling. You define a tool using &lt;code&gt;defineTool&lt;/code&gt; with a schema (powered by Zod), and Copilot decides when to call it. Here's what the core of it looks like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight typescript"&gt;&lt;code&gt;&lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;queryTool&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nf"&gt;defineTool&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;query_time_data&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="na"&gt;description&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Execute a read-only Cosmos DB SQL query against time entries&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="na"&gt;parameters&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;object&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
    &lt;span class="na"&gt;query&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="nx"&gt;z&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;string&lt;/span&gt;&lt;span class="p"&gt;().&lt;/span&gt;&lt;span class="nf"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;Cosmos DB SQL query&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
  &lt;span class="p"&gt;}),&lt;/span&gt;
  &lt;span class="na"&gt;handler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="k"&gt;async &lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt; &lt;span class="o"&gt;=&amp;gt;&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
    &lt;span class="c1"&gt;// query is scoped to the user's partition key&lt;/span&gt;
    &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;result&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;runQuery&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;userId&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;query&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
    &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;JSON&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;stringify&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;

&lt;span class="nx"&gt;session&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nx"&gt;client&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;createSession&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;
  &lt;span class="na"&gt;tools&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="nx"&gt;queryTool&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
  &lt;span class="na"&gt;systemMessage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;mode&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;replace&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;content&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;...&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt; &lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;When a user asks &lt;em&gt;"what was my most productive day this week?"&lt;/em&gt;, the model generates a SQL query, executes it against Cosmos DB (scoped to the user's partition key), and returns a conversational answer. If the generated SQL hits a Cosmos DB error — say, an unsupported &lt;code&gt;ORDER BY&lt;/code&gt; on an aggregate alias — the error is returned to the model as a tool result. The model reads it, adjusts the query, and retries. This usually succeeds within 1–2 attempts, with no user intervention.&lt;/p&gt;

&lt;p&gt;Here's the overall flow:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+--------------+     +----------------+     +-------------+
|  Electron UI | --&amp;gt; |  Copilot SDK   | --&amp;gt; | Copilot CLI |
|  (renderer)  |     |  (main process)|     |  (sidecar)  |
+--------------+     +----------------+     +------+------+
       ^                                           |
       |                                    tool call: query_time_data
       |                                           |
       |                                    +------v------+
       |                                    |  Cosmos DB  |
       |                                    +------+------+
       |                                           |
       |                                     result or error
       |                                           |
       |                                    +------v------+
       |                                    |    Model    |
       |                                    | (interpret) |
       |                                    +------+------+
       |                                      |         |
       |                                success?     SQL error?
       |                                   |          retry with
       |                                   |        corrected SQL
       |                                   |             |
       +---  AI response  &amp;lt;---------------+     (back to Cosmos DB)
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Because the AI writes arbitrary SQL rather than picking from canned reports, the range of questions is wide. A few examples:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;em&gt;Do I tend to work longer hours early in the week or late in the week?&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;How does my Monday workload compare to Friday?&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Compare my total hours this week vs last week&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Rank my projects by total hours and show the percentage each represents&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;Summarize my last two weeks in 3 bullet points&lt;/em&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkw68kk9he0c8808x1pqr.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fkw68kk9he0c8808x1pqr.png" alt="Report view and AI-generated query results" width="800" height="514"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;The app uses GPT-4.1 by default, but you can switch to any &lt;a href="https://docs.github.com/en/copilot/reference/ai-models/supported-models" rel="noopener noreferrer"&gt;supported Copilot model&lt;/a&gt; — &lt;code&gt;gpt-5&lt;/code&gt;, &lt;code&gt;claude-sonnet-4.5&lt;/code&gt;, etc. — by setting &lt;code&gt;COPILOT_MODEL&lt;/code&gt; in &lt;code&gt;.env&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;If you want to go beyond Copilot's model lineup entirely, the app supports &lt;a href="https://github.com/github/copilot-sdk/blob/main/docs/guides/setup/byok.md" rel="noopener noreferrer"&gt;BYOK&lt;/a&gt; (Bring Your Own Key). Point it at your own &lt;a href="https://learn.microsoft.com/en-us/azure/ai-foundry/" rel="noopener noreferrer"&gt;Azure AI Foundry&lt;/a&gt; deployment — set your endpoint, API key, and deployment name in &lt;code&gt;.env&lt;/code&gt; and the SDK routes all AI calls to your model. The tool calling, session management, and agent runtime stay identical. You control the model, the billing, and the identity layer; the SDK provides the agentic infrastructure.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;The app also has experimental support for local OpenAI-compatible servers (Ollama, Foundry Local), though results vary depending on the model's tool calling capabilities, and your environment setup (GPU, etc).&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Try It Yourself
&lt;/h2&gt;

&lt;p&gt;The full source code is on &lt;a href="https://github.com/abhirockzz/cosmosdb-copilot-sdk-time-tracker" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. You can run it with the &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/emulator-linux" rel="noopener noreferrer"&gt;Cosmos DB vNext emulator&lt;/a&gt; — no Azure account needed — seed sample data, and start asking questions in natural language. Swap in your own model via BYOK if you want full control over the AI layer.&lt;/p&gt;

&lt;p&gt;The Copilot SDK is open source and available for TypeScript, Python, Go, and .NET. Check out the &lt;a href="https://github.com/github/copilot-sdk/tree/main/docs" rel="noopener noreferrer"&gt;docs&lt;/a&gt; to see what else you can build with it.&lt;/p&gt;

</description>
      <category>typescript</category>
      <category>javascript</category>
      <category>github</category>
      <category>agents</category>
    </item>
    <item>
      <title>Agentic Apps with GitHub Copilot SDK</title>
      <dc:creator>Abhishek Gupta</dc:creator>
      <pubDate>Mon, 02 Feb 2026 14:45:46 +0000</pubDate>
      <link>https://dev.to/abhirockzz/agentic-apps-with-github-copilot-sdk-60l</link>
      <guid>https://dev.to/abhirockzz/agentic-apps-with-github-copilot-sdk-60l</guid>
      <description>&lt;p&gt;The GitHub Copilot SDK lets you embed Copilot's AI capabilities directly into your apps — available for Go, Python, TypeScript, and .NET.&lt;/p&gt;

&lt;p&gt;Here's a quick demo of building an agentic application with the &lt;a href="https://github.com/github/copilot-sdk" rel="noopener noreferrer"&gt;SDK&lt;/a&gt; and &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/" rel="noopener noreferrer"&gt;Azure Cosmos DB&lt;/a&gt;. &lt;/p&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/uDsfdOG-PjU"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Flight Diary&lt;/strong&gt; is a sample app where you can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📸 Upload a boarding pass image → Copilot extracts flight details automatically (no separate OCR/vision API needed)&lt;/li&gt;
&lt;li&gt;🗣️ Query your flight history in plain English → Copilot generates and runs Cosmos DB SQL queries behind the scenes&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The part I find interesting is how the SDK handles tool calling. You define the tools, Copilot figures out when and how to use them. For example, when extracting from a boarding pass, it parses the image and calls the save function — all from a single prompt.&lt;/p&gt;

&lt;p&gt;If you want to try it yourself, the code is on &lt;a href="https://github.com/abhirockzz/cosmosdb_copilot_sdk_demo_app" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;. It also works with the &lt;a href="https://learn.microsoft.com/azure/cosmos-db/emulator-linux" rel="noopener noreferrer"&gt;Cosmos DB vNext emulator&lt;/a&gt; for local development.&lt;/p&gt;

</description>
      <category>agents</category>
      <category>go</category>
      <category>database</category>
      <category>ai</category>
    </item>
    <item>
      <title>GitHub Copilot CLI + MCP: Talk to Your Database in Plain English</title>
      <dc:creator>Abhishek Gupta</dc:creator>
      <pubDate>Sat, 24 Jan 2026 11:56:09 +0000</pubDate>
      <link>https://dev.to/abhirockzz/github-copilot-cli-mcp-talk-to-your-database-in-plain-english-3go4</link>
      <guid>https://dev.to/abhirockzz/github-copilot-cli-mcp-talk-to-your-database-in-plain-english-3go4</guid>
      <description>&lt;p&gt;Here is a quick demo of how to interact with &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/" rel="noopener noreferrer"&gt;Azure Cosmos DB&lt;/a&gt; from &lt;a href="https://github.com/features/copilot/cli" rel="noopener noreferrer"&gt;GitHub Copilot CLI&lt;/a&gt; using MCP. This &lt;a href="https://github.com/abhirockzz/mcp_cosmosdb_go" rel="noopener noreferrer"&gt;MCP server&lt;/a&gt; lets you interact with Azure Cosmos DB using plain English instead of writing queries or clicking through the portal. List databases, create containers, run SQL queries, add items — all through natural language. It works with both the Cosmos DB service and the &lt;a href="https://learn.microsoft.com/azure/cosmos-db/emulator-linux" rel="noopener noreferrer"&gt;vNext emulator&lt;/a&gt; (for local development).&lt;/p&gt;

&lt;p&gt;

  &lt;iframe src="https://www.youtube.com/embed/l6gSYNd1Txs"&gt;
  &lt;/iframe&gt;


&lt;/p&gt;

&lt;p&gt;The part I really enjoy is watching Copilot CLI figure out which tools to call to get the job done. For example, when I asked for "pending tasks," it generated the query and ran it without me having to think about the syntax.&lt;/p&gt;

&lt;p&gt;If you want to try it yourself, the code is on &lt;a href="//github.com/abhirockzz/mcp_cosmosdb_go"&gt;GitHub&lt;/a&gt;. It's fairly straightforward to build, and set up with &lt;code&gt;/mcp add&lt;/code&gt;. For something production-ready with remote (HTTP) deployment and Entra ID authentication, check out the &lt;a href="https://github.com/AzureCosmosDB/MCPToolKit" rel="noopener noreferrer"&gt;Azure Cosmos DB MCP Toolkit&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;If you haven't tried &lt;a href="https://docs.github.com/en/copilot/how-tos/use-copilot-agents/use-copilot-cli#add-an-mcp-server" rel="noopener noreferrer"&gt;GitHub Copilot CLI with MCP servers&lt;/a&gt; yet, this is an easy way to get started.&lt;/p&gt;

&lt;p&gt;Cheers!&lt;/p&gt;

</description>
      <category>agents</category>
      <category>go</category>
      <category>mcp</category>
      <category>database</category>
    </item>
    <item>
      <title>Azure Cosmos DB Playground: Learn and experiment with queries in your browser</title>
      <dc:creator>Abhishek Gupta</dc:creator>
      <pubDate>Wed, 14 Jan 2026 07:04:05 +0000</pubDate>
      <link>https://dev.to/abhirockzz/azure-cosmos-db-playground-learn-and-experiment-with-queries-in-your-browser-1o8j</link>
      <guid>https://dev.to/abhirockzz/azure-cosmos-db-playground-learn-and-experiment-with-queries-in-your-browser-1o8j</guid>
      <description>&lt;p&gt;&lt;strong&gt;Interactive Browser-Based Environment to Learn, Test, and Share Queries&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The &lt;a href="https://aka.ms/cosmosdb-playground" rel="noopener noreferrer"&gt;Azure Cosmos DB Playground&lt;/a&gt; is an interactive, browser-based playground for learning and experimenting with &lt;a href="https://learn.microsoft.com/en-us/cosmos-db/query/overview" rel="noopener noreferrer"&gt;Azure Cosmos DB SQL queries&lt;/a&gt; without any setup, installation, or cloud costs. The playground runs on the &lt;a href="https://learn.microsoft.com/en-us/azure/cosmos-db/emulator-linux" rel="noopener noreferrer"&gt;Azure Cosmos DB vNext emulator&lt;/a&gt; and leverages the open-source &lt;a href="https://codapi.org/" rel="noopener noreferrer"&gt;codapi&lt;/a&gt; project behind the scenes.&lt;/p&gt;

&lt;p&gt;The playground is a great tool for learning, prototyping, testing, and sharing Azure Cosmos DB queries. You can:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;📦 Explore with pre-loaded datasets and ready-to-run query examples&lt;/li&gt;
&lt;li&gt;📤 Paste or upload your own JSON data to experiment with custom scenarios&lt;/li&gt;
&lt;li&gt;⚡ Instantly see query results and modify both data and queries on the fly&lt;/li&gt;
&lt;li&gt;🔗 Generate shareable links that capture your current dataset and query for easy sharing&lt;/li&gt;
&lt;li&gt;♻️ Restore your last session automatically after a refresh or reopening the page&lt;/li&gt;
&lt;li&gt;🧩 Embed interactive, runnable examples directly into HTML files for documentation, blogs, or tutorials&lt;/li&gt;
&lt;/ul&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Note:&lt;/strong&gt; This is an experimental project and not an official Microsoft or Azure offering. It’s designed for learning and sharing, not for production use.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;▶️ &lt;strong&gt;Quick Demo&lt;/strong&gt; (click to play)&lt;/p&gt;

&lt;p&gt;&lt;a href="http://abhirockzz.github.io/videos/playground_demo.mp4" rel="noopener noreferrer"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fgithub.com%2Fabhirockzz%2Fcosmosdb-playground%2Fraw%2Fmain%2Fimages%2Fplayground.png" alt="Playground Demo" width="800" height="1110"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Try the Playground (or Deploy Your Own) 🚀
&lt;/h2&gt;

&lt;p&gt;You can head over to &lt;strong&gt;&lt;a href="https://aka.ms/cosmosdb-playground" rel="noopener noreferrer"&gt;https://aka.ms/cosmosdb-playground&lt;/a&gt;&lt;/strong&gt; and start experimenting right away!&lt;/p&gt;

&lt;p&gt;While the &lt;a href="https://aka.ms/cosmosdb-playground" rel="noopener noreferrer"&gt;hosted playground&lt;/a&gt; is ready to use, you can also deploy your own instance on Azure. The playground uses a fully containerized architecture with Docker Compose. Follow the detailed deployment instructions available on &lt;a href="https://github.com/abhirockzz/cosmosdb-playground/blob/main/docs/azure-deployment.md" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt; to set up your own playground instance.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;To configure HTTP(s) access for your deployed playground, refer to the instructions available on &lt;a href="https://github.com/abhirockzz/cosmosdb-playground/blob/main/docs/https-setup.md" rel="noopener noreferrer"&gt;GitHub&lt;/a&gt;.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;Playground Features&lt;/strong&gt; 🛠️&lt;/p&gt;

&lt;p&gt;These might evolve over time - You can check out the GitHub repository for up to date &lt;a href="https://github.com/abhirockzz/cosmosdb-playground/blob/main/docs/features.md" rel="noopener noreferrer"&gt;list of features&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Behind the Scenes 🏗️
&lt;/h2&gt;

&lt;p&gt;Here is a simplified architecture of the Azure Cosmos DB Playground:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;+-------------------+        +-------------------+        +-------------------+
|   User Browser    |  &amp;lt;---&amp;gt; |      nginx        |  &amp;lt;---&amp;gt; |     Codapi        |
| (playground.html) |        | (Reverse Proxy)   |        | (Sandbox Server)  |
+-------------------+        +-------------------+        +-------------------+
                                                           |
                                                           v
                                                +--------------------------+
                                                |  Ephemeral Query Container|
                                                |  (Python + Cosmos SDK)    |
                                                +--------------------------+
                                                           |
                                                           v
                                                +--------------------------+
                                                | Cosmos DB Emulator       |
                                                | (Docker Container)       |
                                                +--------------------------+
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;At its core, the playground uses the Azure Cosmos DB vNext Emulator as a custom Codapi &lt;a href="https://github.com/nalgeon/codapi/blob/main/docs/add-sandbox.md" rel="noopener noreferrer"&gt;sandbox&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Azure Cosmos DB vNext Emulator&lt;/strong&gt;: This is a &lt;strong&gt;local&lt;/strong&gt; version of Azure Cosmos DB (SQL API) available as a Docker container. It &lt;em&gt;emulates&lt;/em&gt; the real Azure Cosmos DB service, so you can experiment with queries and data models without any cloud setup or cost.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Codapi&lt;/strong&gt;: It is a lightweight sandbox server designed for interactive documentation, code examples, and learning environments. In the playground, Codapi manages the creation of isolated Docker containers for each query execution. This ensures that each user’s code and data are executed in an ephemeral environment. Codapi JavaScript widget (&lt;a href="https://github.com/nalgeon/codapi-js" rel="noopener noreferrer"&gt;codapi-js&lt;/a&gt;) is used for the playground frontend integration, which invokes the &lt;a href="https://github.com/nalgeon/codapi/blob/main/docs/api.md" rel="noopener noreferrer"&gt;Codapi API&lt;/a&gt; for code execution in the sandbox.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Query Execution Flow&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;code&gt;nginx&lt;/code&gt; serves the frontend and routes API requests to Codapi, enabling interactive query execution from the browser.&lt;/p&gt;

&lt;p&gt;For each run, Codapi spawns an ephemeral query Docker container where a Python component connects to the long-running Cosmos DB emulator. It creates a temporary Cosmos DB container, seeds the data, executes the query, and returns results. After execution, both the temporary Cosmos DB container and the ephemeral query Docker container are cleaned up.&lt;/p&gt;

&lt;h2&gt;
  
  
  Limitations ⚠️
&lt;/h2&gt;

&lt;p&gt;The playground is a sandbox for learning and experimentation, not production use. It is designed for small(ish) datasets and may have performance constraints, among other limitations. Some of these limitations may change over time. For the most current list, refer to the &lt;a href="https://github.com/abhirockzz/cosmosdb-playground/tree/main/docs" rel="noopener noreferrer"&gt;GitHub repo&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try It Out! ✨
&lt;/h2&gt;

&lt;p&gt;Visit &lt;strong&gt;&lt;a href="https://aka.ms/cosmosdb-playground" rel="noopener noreferrer"&gt;https://aka.ms/cosmosdb-playground&lt;/a&gt;&lt;/strong&gt; to start experimenting with queries, and share your examples with others.&lt;/p&gt;

&lt;p&gt;Have feedback or suggestions? Visit the &lt;a href="https://github.com/abhirockzz/cosmosdb-playground" rel="noopener noreferrer"&gt;GitHub repository&lt;/a&gt; and share your thoughts. Happy querying!&lt;/p&gt;

</description>
      <category>docker</category>
      <category>python</category>
      <category>javascript</category>
      <category>webdev</category>
    </item>
  </channel>
</rss>
