§ Documentation
Database
In-memory NoSQL document/key-value store modelled on DynamoDB, Cosmos DB, and Firestore, driven with the real cloud SDKs
aws DynamoDBazr Cosmos DBgcp Firestore
Emulates a managed NoSQL store — the DynamoDB/Cosmos/Firestore table your app writes items to and queries by key. You create a table with a partition key (and optional sort key), then put, get, update, query, and scan schemaless items. Each item is just a map of attributes; the table indexes them by their key so lookups and range queries stay fast.
Reach for it when your code puts an item and reads it back by key, runs a query with a key condition, or scans with a filter — so you can exercise those paths without a real DynamoDB account. For managed relational databases (RDS/Aurora, Azure SQL, Cloud SQL), see Relational Database instead.
| Provider | Service | SDK-compat | Driver |
|---|---|---|---|
| AWS | DynamoDB | ✓ Live | aws.DynamoDB |
| Azure | Cosmos DB | ✓ Live | azure.CosmosDB |
| GCP | Firestore | ✓ Live | gcp.Firestore |
Drive it with the real SDK#
Run cloudemu as a server and point the real SDK at it, so your production data-access code runs unchanged. Start it with cloudemu serve (or docker run --rm -p 4566:4566 ghcr.io/stackshy/cloudemu), which serves the AWS API on http://localhost:4566:
cloudemu serve # AWS API on http://localhost:4566Then point the stock DynamoDB client at that endpoint — only the endpoint is redirected — and create a table keyed on id and write one item:
import (
"github.com/aws/aws-sdk-go-v2/service/dynamodb"
"github.com/aws/aws-sdk-go-v2/service/dynamodb/types"
)
client := dynamodb.NewFromConfig(cfg, func(o *dynamodb.Options) {
o.BaseEndpoint = aws.String("http://localhost:4566")
})
client.CreateTable(ctx, &dynamodb.CreateTableInput{
TableName: aws.String("Users"),
AttributeDefinitions: []types.AttributeDefinition{
{AttributeName: aws.String("id"), AttributeType: types.ScalarAttributeTypeS},
},
KeySchema: []types.KeySchemaElement{
{AttributeName: aws.String("id"), KeyType: types.KeyTypeHash},
},
BillingMode: types.BillingModePayPerRequest,
})
client.PutItem(ctx, &dynamodb.PutItemInput{
TableName: aws.String("Users"),
Item: map[string]types.AttributeValue{
"id": &types.AttributeValueMemberS{Value: "u1"},
"name": &types.AttributeValueMemberS{Value: "Alice"},
},
})Same shape with azcosmos (Azure) and cloud.google.com/go/firestore (GCP). See the SDK-Compat Server page for the full quick starts.
In-process (Go unit tests)#
For Go unit tests written inside cloudemu-aware code, stand the same wire server up in-process with httptest.NewServer and point the client at ts.URL. The Drivers you pass name exactly the drivers this service needs:
import (
"github.com/stackshy/cloudemu/v2"
awsserver "github.com/stackshy/cloudemu/v2/server/aws"
)
cloud := cloudemu.NewAWS()
ts := httptest.NewServer(awsserver.New(awsserver.Drivers{DynamoDB: cloud.DynamoDB}))
defer ts.Close()
// point the same dynamodb client at ts.URL instead of the running endpointCall the driver directly#
For in-process setup or assertions you can skip the HTTP hop and call the driver. Items are plain map[string]any, so there's no attribute-value wrapping to deal with:
import dbdriver "github.com/stackshy/cloudemu/v2/services/database/driver"
aws.DynamoDB.CreateTable(ctx, dbdriver.TableConfig{
Name: "Users", PartitionKey: "id",
})
aws.DynamoDB.PutItem(ctx, "Users", map[string]any{"id": "u1", "name": "Alice"})
item, _ := aws.DynamoDB.GetItem(ctx, "Users", map[string]any{"id": "u1"})GetItem takes just the key attributes and returns the full item (or nil if absent). Query, Scan, UpdateItem, and batch/transactional writes take the same shape via dbdriver input structs.
Behavior & fidelity#
| Behavior | What happens |
|---|---|
| Query and scan paginate | Results come back in stable key order; pass a Limit and resume with an offset PageToken or a DynamoDB-style ExclusiveStartKey, and page tokens stay valid across calls. |
| Numeric-aware comparisons | Numbers order numerically ("10" > "9"), strings lexically, and bools false < true, matching the real services rather than naive string compare. |
| TTL expiry on read | An item past its TTL attribute reads as absent, so a Get or Query never returns expired data. |
| Streams / change feed | With streams enabled, writes emit INSERT / MODIFY / REMOVE records you can read back — useful for change-driven pipelines. |
| Global secondary indexes | GSIs can be created, described, listed, and deleted, and a Query can target one via its IndexName. |
Query & expression fidelity#
The expression and query grammars are evaluated for real in memory, not approximated — so a query with a real filter returns exactly the items the cloud would.
- DynamoDB —
FilterExpressionandConditionExpression(a conditional write fails when its condition is false),KeyConditionwithbegins_with/BETWEEN,ProjectionExpression, and the fullUpdateExpressiongrammar (ADD/DELETE, arithmetic,if_not_exists,list_append) with real set types. - Firestore — structured-query
WHEREwithOR/IN/array-contains/ unary operators, plusorderBy, cursors, andselectprojection. - Cosmos DB — SQL query support over the document store.
SDK-compat — Live#
Real dynamodb, azcosmos, and Firestore clients drive it end-to-end — see SDK-Compat for the full operation list.