skills/microservice/cosmos/partition-strategy/SKILL.md
Use when choosing partition keys or handling cross-partition queries in Cosmos DB.
npx skillsauth add faysilalshareef/dotnet-ai-kit partition-strategyInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
// Container definition with 3-level partition key
var containerProperties = new ContainerProperties
{
Id = "invoices",
PartitionKeyPaths = new Collection<string>
{
"/merchantId", // Level 1: tenant/merchant isolation
"/reportMonth", // Level 2: time-based partitioning
"/discriminator" // Level 3: entity type
}
};
// Full 3-level key for point reads/writes
public PartitionKey PartitionKeys => new PartitionKeyBuilder()
.Add(MerchantId) // Level 1
.Add(ReportMonth) // Level 2
.Add(Discriminator) // Level 3
.Build();
// Partial key for scoped queries (Level 1 only)
public static PartitionKey ForMerchant(string merchantId) =>
new PartitionKeyBuilder()
.Add(merchantId)
.Build();
// Partial key for time-scoped queries (Level 1 + 2)
public static PartitionKey ForMerchantMonth(string merchantId, string month) =>
new PartitionKeyBuilder()
.Add(merchantId)
.Add(month)
.Build();
// Fastest: Point read with full partition key
var invoice = await container.ReadItemAsync<SaleInvoice>(
id, SaleInvoice.ForMerchantMonth("M001", "2025-03"));
// Fast: Query within full partition
var invoices = await repo.QueryAsync(
i => i.TotalAmount > 1000,
SaleInvoice.ForMerchantMonth("M001", "2025-03"));
// Medium: Query with partial partition key (fan-out within merchant)
var allInvoices = await repo.QueryAsync(
i => i.TotalAmount > 1000,
SaleInvoice.ForMerchant("M001"));
// Slow: Cross-partition query (avoid in production hot paths)
var report = await repo.QueryAsync(
i => i.TotalAmount > 10000);
Query Pattern | Recommended Partition Key
-------------------------------- | -------------------------
Single tenant, time-series | TenantId / Year-Month / EntityType
Multi-tenant, per-user data | TenantId / UserId / EntityType
Geographic data | Region / City / EntityType
Order processing | CustomerId / OrderDate / EntityType
IoT telemetry | DeviceId / Date / EntityType
Pattern 1: Entity-per-container
- invoices container → SaleInvoice documents
- reports container → MerchantSalesReport documents
- Simple, clear boundaries
- Best for independent entity lifecycles
Pattern 2: Polymorphic container
- sales container → SaleInvoice + SoldItem + SalesReport
- Uses Discriminator for filtering
- Enables TransactionalBatch across types
- Best when entities share partition key and need atomic operations
| Anti-Pattern | Correct Approach | |---|---| | Using entity Id as partition key | Choose keys based on query patterns | | Single-value partition key | Use hierarchical keys for flexibility | | Timestamp as only partition key | Causes hot partitions on recent data | | Cross-partition queries in hot paths | Design partitions around common queries | | Ignoring RU costs | Monitor and optimize partition strategy |
# Find partition key definitions
grep -r "PartitionKeyBuilder\|PartitionKeyPaths" --include="*.cs" src/
# Find container properties
grep -r "ContainerProperties\|ContainerName" --include="*.cs" src/
# Find cross-partition queries
grep -r "ToListWithoutPartitionFilter\|EnableCrossPartition" --include="*.cs" src/
data-ai
Use when about to claim work is complete, fixed, passing, or ready — before committing, creating PRs, or moving to the next task. Requires running verification commands and confirming output before making any success claims.
development
Use when encountering any bug, test failure, build error, or unexpected behavior — before proposing fixes or making changes.
development
Use when checkpointing, wrapping up, or handing off an AI-assisted development session.
development
Use when following the Specification-Driven Development lifecycle from plan through ship.