Skip to content

Multi Database

Aryeh Citron edited this page Apr 20, 2026 · 3 revisions

For codebases where a single CosmosClient talks to multiple databases that may have overlapping container names (e.g. users-db/events and orders-db/events).

Single-database? If all your containers are in one database, you don't need this page — just use InMemoryCosmos.Create() or InMemoryCosmos.Builder().AddContainer(...). See Getting Started.

Setup

using var cosmos = InMemoryCosmos.Builder()
    .AddDatabase("users-db", db => {
        db.AddContainer("events", "/userId");
        db.AddContainer("profiles", "/userId");
    })
    .AddDatabase("orders-db", db => {
        db.AddContainer("events", "/orderId");
        db.AddContainer("products", "/categoryId");
    })
    .Build();

Database-Scoped Access

// Containers scoped to a database
var userEvents = cosmos.Database("users-db").Containers["events"];
var orderEvents = cosmos.Database("orders-db").Containers["events"];

// Test setup scoped to a database
cosmos.Database("users-db").SetupContainer("events").RegisterUdf("myUdf", args => args[0]);

// Fault injection scoped to a database
cosmos.Database("orders-db").SetFaultInjector(req =>
    new HttpResponseMessage((HttpStatusCode)503));

// Handler access scoped to a database
var handler = cosmos.Database("orders-db").GetHandler("events");

Flat Access (Unique Names)

When container names are globally unique across all databases, flat access works:

using var cosmos = InMemoryCosmos.Builder()
    .AddDatabase("users-db", db => db.AddContainer("profiles", "/userId"))
    .AddDatabase("orders-db", db => db.AddContainer("orders", "/orderId"))
    .Build();

// Flat access works — names are unique
var profiles = cosmos.Containers["profiles"];
var orders = cosmos.Containers["orders"];
cosmos.ClearItems("profiles");
cosmos.GetHandler("orders").FaultInjector = ...;

Ambiguity Handling

When container names collide across databases, flat access throws with guidance:

using var cosmos = InMemoryCosmos.Builder()
    .AddDatabase("users-db", db => db.AddContainer("events", "/userId"))
    .AddDatabase("orders-db", db => db.AddContainer("events", "/orderId"))
    .Build();

// ❌ Throws KeyNotFoundException:
//    "Container 'events' exists in multiple databases: orders-db, users-db.
//     Use cosmos.Database("...").Containers["events"] instead."
var events = cosmos.Containers["events"];

// ✅ Use database-scoped access instead
var userEvents = cosmos.Database("users-db").Containers["events"];
var orderEvents = cosmos.Database("orders-db").Containers["events"];

The same ambiguity detection applies to SetupContainer(), GetHandler(), and Handlers.

Mixing AddContainer() and AddDatabase()

AddContainer() adds to the default database ("default"). You can mix both:

using var cosmos = InMemoryCosmos.Builder()
    .AddContainer("orders", "/customerId")           // goes to "default" database
    .AddDatabase("audit-db", db => {
        db.AddContainer("audit-events", "/eventId"); // goes to "audit-db"
    })
    .Build();

// Flat access works — names are globally unique
var orders = cosmos.Containers["orders"];
var events = cosmos.Containers["audit-events"];

// Database-scoped access also works
var eventsToo = cosmos.Database("audit-db").Containers["audit-events"];

Databases Property

Enumerate all configured databases:

foreach (var (name, dbResult) in cosmos.Databases)
{
    Console.WriteLine($"Database: {name}");
    foreach (var (containerName, _) in dbResult.Containers)
        Console.WriteLine($"  Container: {containerName}");
}

InMemoryDatabaseResult API

Member Description
DatabaseName The database name
Containers SDK Container references keyed by name
SetupContainer(name) Returns IContainerTestSetup for the container
GetHandler(name) Returns the FakeCosmosHandler for the container
Handlers All handlers keyed by container name
SetFaultInjector(injector) Sets/clears fault injector on all handlers in this database

Dynamic Container Creation

Containers created at runtime via CreateContainerAsync are scoped to the database in the URL path. They appear in the appropriate InMemoryDatabaseResult and follow the same ambiguity rules for flat access.

Clone this wiki locally