Public Preview
This SDK is currently available as a public preview and is not yet fully ready for production use. Expect breaking changes, incomplete features, and limited support during this phase.
Why Multicloud DB?¶
| Challenge | How the SDK helps |
|---|---|
| Vendor lock-in | Single MulticloudDbClient interface - portable CRUD + query |
| Divergent query languages | Portable DSL auto-translated to Cosmos SQL, PartiQL, or GoogleSQL |
| Migration pain | Switch providers by changing one property - zero code changes |
| Feature uncertainty | Runtime CapabilitySet introspection with portability warnings |
| Cross-provider testing | Conformance suite runs identical tests against every provider |
Key Features¶
Write Once, Run Anywhere¶
Single MulticloudDbClient interface for CRUD and query operations.
Switch providers by changing one config property - zero code changes.
Portable Query DSL¶
Write WHERE-clause filters once using a SQL-subset syntax with named parameters. Automatically translated to Cosmos SQL, DynamoDB PartiQL, or Spanner GoogleSQL.
Capability Introspection¶
Query provider capabilities at runtime. Get clear signals when a feature is unavailable or behaviour may differ across providers.
Multi-Tenant Patterns¶
Database-per-tenant isolation via ResourceAddress routing.
Partition-scoped queries for efficient within-partition reads.
Conformance Testing¶
281+ tests across API and provider modules. Identical CRUD + query tests run against every provider emulator.
Provider Diagnostics¶
Structured diagnostics with latency, request charge (RU), and provider correlation IDs. SLF4J structured logging for production monitoring.
Architecture¶
graph TD
APP["<b>Your Application</b><br/>code against Multicloud DB API"]
API["<b>MulticloudDbClient</b><br/>multiclouddb-api<br/><i>CRUD · Query · Capabilities</i>"]
SL(("ServiceLoader"))
COSMOS["<b>Cosmos DB</b><br/>Provider"]
DYNAMO["<b>DynamoDB</b><br/>Provider"]
SPANNER["<b>Spanner</b><br/>Provider"]
APP --> API
API --> SL
SL --> COSMOS
SL --> DYNAMO
SL --> SPANNER
Providers are discovered at runtime via Java's ServiceLoader - no provider
imports in application code. Drop the provider JAR on the classpath and
configure via properties.
Learn more about the architecture
Supported Providers¶
| Provider | Module | Status | Native SDK |
|---|---|---|---|
| Azure Cosmos DB | multiclouddb-provider-cosmos |
Full | Azure Cosmos Java SDK |
| Amazon DynamoDB | multiclouddb-provider-dynamo |
Full | AWS SDK for Java 2.x |
| Google Cloud Spanner | multiclouddb-provider-spanner |
Source only* | Google Cloud Spanner |
* The Spanner provider source code and conformance tests are included in the repository, but Maven artifacts are not yet published. Spanner artifacts will be available in a future release.
Sample Applications¶
Sample applications are maintained in a separate repository: microsoft/multiclouddb-sdk-for-java-samples
| Sample | Description | Details |
|---|---|---|
| Portable CRUD + Query | Minimal end-to-end CRUD and query sample | View guide → |
| TODO App | Simple CRUD web app with browser UI | View guide → |
| Risk Analysis Platform | Multi-tenant portfolio risk analytics with executive dashboard | View guide → |
Quick Example¶
// Configure - provider selected entirely by config
Properties props = new Properties();
props.load(getClass().getResourceAsStream("/app.properties"));
MulticloudDbClientConfig config = MulticloudDbClientConfig.builder()
.provider(ProviderId.fromId(props.getProperty("multiclouddb.provider")))
.connection("endpoint", props.getProperty("multiclouddb.connection.endpoint"))
// Auth properties (key, credentials, etc.) are loaded from the
// properties file. See Configuration Reference for recommended
// identity-based auth patterns for each provider.
.build();
try (MulticloudDbClient client = MulticloudDbClientFactory.create(config)) {
// CRUD - same code for every provider
ResourceAddress todos = new ResourceAddress("mydb", "todos");
MulticloudDbKey key = MulticloudDbKey.of("todo-1", "todo-1");
Map<String, Object> doc = Map.of(
"id", "todo-1",
"status", "active",
"category", "shopping"
);
client.upsert(todos, key, doc);
// Query with portable expressions - auto-translated per provider
QueryRequest query = QueryRequest.builder()
.expression("status = @status AND category = @cat")
.parameters(Map.of("status", "active", "cat", "shopping"))
.maxPageSize(25)
.build();
QueryPage page = client.query(todos, query);
}
