Your developers' primary job is to ship features that create customer value, not to wrestle with database complexity. The StatelyDB SDK is engineered for productivity, providing a high-level, intuitive API that eliminates the boilerplate and operational overhead required by other databases. By generating type-safe client code directly from your Elastic Schema™, we turn your data model into a powerful, easy-to-use SDK that feels like a natural extension of your application.
Databases like AWS DynamoDB force developers to work with low-level, verbose APIs. A simple operation, like creating a new user with a unique email address, requires hundreds of lines of code to manually validate inputs, marshal objects into attribute maps, construct transaction items, and handle complex error conditions.
This is what that looks like with the raw AWS SDK for Go:
**Raw DynamoDB (Go):**
func (c *DynamoDBClient) CreateUser(ctx context.Context, displayName, email string) (*User, error) {
if displayName == "" { // Manual validation
return nil, fmt.Errorf("display name cannot be empty")
}
if email == "" {
return nil, fmt.Errorf("email cannot be empty")
}
if !emailRegex.MatchString(email) {
return nil, fmt.Errorf("invalid email format")
}
user := &User{
ID: uuid.New(),
DisplayName: displayName,
Email: email,
}
// Manually marshal the object to a DynamoDB attribute map
userAV, err := attributevalue.MarshalMap(user)
if err != nil {
return nil, fmt.Errorf("failed to marshal user: %w", err)
}
userAV["PK"] = &types.AttributeValueMemberS{
Value: fmt.Sprintf("USER#%s", user.ID.String()),
}
userAV["SK"] = &types.AttributeValueMemberS{
Value: "METADATA",
}
// Manually create a second record for the email lookup/uniqueness check
emailAV := maps.Clone(userAV)
emailAV["PK"] = &types.AttributeValueMemberS{
Value: fmt.Sprintf("EMAIL#%s", email),
}
emailAV["SK"] = &types.AttributeValueMemberS{
Value: "METADATA",
}
// Manually construct a transaction to write both records
_, err = c.client.TransactWriteItems(ctx, &dynamodb.TransactWriteItemsInput{
TransactItems: []types.TransactWriteItem{
{
Put: &types.Put{
TableName: aws.String(c.table),
Item: userAV,
},
},
{
Put: &types.Put{
TableName: aws.String(c.table),
Item: emailAV,
ConditionExpression: aws.String("attribute_not_exists(PK)"), // Uniqueness check
},
},
},
})
// Manually parse complex error responses
if err != nil {
var txErr *types.TransactionCanceledException
if errors.As(err, &txErr) {
for _, reason := range txErr.CancellationReasons {
if reason.Code != nil && *reason.Code == "ConditionalCheckFailed" {
return nil, fmt.Errorf("email %s is already in use", email)
}
}
}
return nil, fmt.Errorf("failed to create user: %w", err)
}
return user, nil
}
With StatelyDB, the same operation is a single, intuitive line of code. Our schema-aware client handles validation, ID generation, and transactional writes automatically.
**StatelyDB (Go):**
user, err := client.Put(ctx, &schema.User{
DisplayName: "Stately Support",
Email: "support@stately.cloud",
})
// ... handle errorThis radical simplicity allows your developers to be productive from day one, onboard new team members faster, and focus their talent on building your product, not managing the database.
Databases like AWS DynamoDB force developers to work with low-level, verbose APIs. A simple operation, like creating a new user with a unique email address, requires hundreds of lines of code to manually validate inputs, marshal objects into attribute maps, construct transaction items, and handle complex error conditions.
This is what that looks like with the raw AWS SDK for Go:
**Raw DynamoDB (Go):**
func (c *DynamoDBClient) CreateUser(ctx context.Context, displayName, email string) (*User, error) {
if displayName == "" { // Manual validation
return nil, fmt.Errorf("display name cannot be empty")
}
if email == "" {
return nil, fmt.Errorf("email cannot be empty")
}
if !emailRegex.MatchString(email) {
return nil, fmt.Errorf("invalid email format")
}
user := &User{
ID: uuid.New(),
DisplayName: displayName,
Email: email,
}
// Manually marshal the object to a DynamoDB attribute map
userAV, err := attributevalue.MarshalMap(user)
if err != nil {
return nil, fmt.Errorf("failed to marshal user: %w", err)
}
userAV["PK"] = &types.AttributeValueMemberS{
Value: fmt.Sprintf("USER#%s", user.ID.String()),
}
userAV["SK"] = &types.AttributeValueMemberS{
Value: "METADATA",
}
// Manually create a second record for the email lookup/uniqueness check
emailAV := maps.Clone(userAV)
emailAV["PK"] = &types.AttributeValueMemberS{
Value: fmt.Sprintf("EMAIL#%s", email),
}
emailAV["SK"] = &types.AttributeValueMemberS{
Value: "METADATA",
}
// Manually construct a transaction to write both records
_, err = c.client.TransactWriteItems(ctx, &dynamodb.TransactWriteItemsInput{
TransactItems: []types.TransactWriteItem{
{
Put: &types.Put{
TableName: aws.String(c.table),
Item: userAV,
},
},
{
Put: &types.Put{
TableName: aws.String(c.table),
Item: emailAV,
ConditionExpression: aws.String("attribute_not_exists(PK)"), // Uniqueness check
},
},
},
})
// Manually parse complex error responses
if err != nil {
var txErr *types.TransactionCanceledException
if errors.As(err, &txErr) {
for _, reason := range txErr.CancellationReasons {
if reason.Code != nil && *reason.Code == "ConditionalCheckFailed" {
return nil, fmt.Errorf("email %s is already in use", email)
}
}
}
return nil, fmt.Errorf("failed to create user: %w", err)
}
return user, nil
}
With StatelyDB, the same operation is a single, intuitive line of code. Our schema-aware client handles validation, ID generation, and transactional writes automatically.
**StatelyDB (Go):**
user, err := client.Put(ctx, &schema.User{
DisplayName: "Stately Support",
Email: "support@stately.cloud",
})
// ... handle errorDatabases like AWS DynamoDB force developers to work with low-level, verbose APIs. A simple operation, like creating a new user with a unique email address, requires hundreds of lines of code to manually validate inputs, marshal objects into attribute maps, construct transaction items, and handle complex error conditions.
This is what that looks like with the raw AWS SDK for Go:
**Raw DynamoDB (Go):**
func (c *DynamoDBClient) CreateUser(ctx context.Context, displayName, email string) (*User, error) {
if displayName == "" { // Manual validation
return nil, fmt.Errorf("display name cannot be empty")
}
if email == "" {
return nil, fmt.Errorf("email cannot be empty")
}
if !emailRegex.MatchString(email) {
return nil, fmt.Errorf("invalid email format")
}
user := &User{
ID: uuid.New(),
DisplayName: displayName,
Email: email,
}
// Manually marshal the object to a DynamoDB attribute map
userAV, err := attributevalue.MarshalMap(user)
if err != nil {
return nil, fmt.Errorf("failed to marshal user: %w", err)
}
userAV["PK"] = &types.AttributeValueMemberS{
Value: fmt.Sprintf("USER#%s", user.ID.String()),
}
userAV["SK"] = &types.AttributeValueMemberS{
Value: "METADATA",
}
// Manually create a second record for the email lookup/uniqueness check
emailAV := maps.Clone(userAV)
emailAV["PK"] = &types.AttributeValueMemberS{
Value: fmt.Sprintf("EMAIL#%s", email),
}
emailAV["SK"] = &types.AttributeValueMemberS{
Value: "METADATA",
}
// Manually construct a transaction to write both records
_, err = c.client.TransactWriteItems(ctx, &dynamodb.TransactWriteItemsInput{
TransactItems: []types.TransactWriteItem{
{
Put: &types.Put{
TableName: aws.String(c.table),
Item: userAV,
},
},
{
Put: &types.Put{
TableName: aws.String(c.table),
Item: emailAV,
ConditionExpression: aws.String("attribute_not_exists(PK)"), // Uniqueness check
},
},
},
})
// Manually parse complex error responses
if err != nil {
var txErr *types.TransactionCanceledException
if errors.As(err, &txErr) {
for _, reason := range txErr.CancellationReasons {
if reason.Code != nil && *reason.Code == "ConditionalCheckFailed" {
return nil, fmt.Errorf("email %s is already in use", email)
}
}
}
return nil, fmt.Errorf("failed to create user: %w", err)
}
return user, nil
}
With StatelyDB, the same operation is a single, intuitive line of code. Our schema-aware client handles validation, ID generation, and transactional writes automatically.
**StatelyDB (Go):**
user, err := client.Put(ctx, &schema.User{
DisplayName: "Stately Support",
Email: "support@stately.cloud",
})
// ... handle errorThis radical simplicity allows your developers to be productive from day one, onboard new team members faster, and focus their talent on building your product, not managing the database.
Our entire platform is designed around a streamlined developer workflow that eliminates friction and accelerates feature delivery.
Define your data model once in our simple schema language, and the stately CLI generates idiomatic, type-safe client code for your favorite programming languages. You work with your own objects (User, Order), not generic maps or documents. This means you catch errors at compile time, not in production, and your editor's autocomplete becomes a powerful tool for discovery.
Define your data model once in our simple schema language, and the stately CLI generates idiomatic, type-safe client code for your favorite programming languages. You work with your own objects (User, Order), not generic maps or documents. This means you catch errors at compile time, not in production, and your editor's autocomplete becomes a powerful tool for discovery.
The StatelyDB API surface is intentionally small and easy to master. Instead of dozens of complex operations and query languages, you work with a handful of simple, powerful methods:
This streamlined API eliminates the steep learning curve and performance surprises common with other databases.
The StatelyDB API surface is intentionally small and easy to master. Instead of dozens of complex operations and query languages, you work with a handful of simple, powerful methods:
This streamlined API eliminates the steep learning curve and performance surprises common with other databases.
Because StatelyDB is powered by Elastic Schema, developers can change the data model at any time without fear. There's no need to coordinate application deployments with database changes. Just update your schema, generate your new client, and deploy. Old clients continue to work, and new clients can use the new data model immediately.
Because StatelyDB is powered by Elastic Schema, developers can change the data model at any time without fear. There's no need to coordinate application deployments with database changes. Just update your schema, generate your new client, and deploy. Old clients continue to work, and new clients can use the new data model immediately.
Our entire platform is designed around a streamlined developer workflow that eliminates friction and accelerates feature delivery.
Define your data model once in our simple schema language, and the stately CLI generates idiomatic, type-safe client code for your favorite programming languages. You work with your own objects (User, Order), not generic maps or documents. This means you catch errors at compile time, not in production, and your editor's autocomplete becomes a powerful tool for discovery.
The StatelyDB API surface is intentionally small and easy to master. Instead of dozens of complex operations and query languages, you work with a handful of simple, powerful methods:
This streamlined API eliminates the steep learning curve and performance surprises common with other databases.
Because StatelyDB is powered by Elastic Schema, developers can change the data model at any time without fear. There's no need to coordinate application deployments with database changes. Just update your schema, generate your new client, and deploy. Old clients continue to work, and new clients can use the new data model immediately.
Our entire platform is designed around a streamlined developer workflow that eliminates friction and accelerates feature delivery.
DynamoDB is a powerful storage engine, but its raw API forces immense complexity onto your application layer. Developers must manually handle object mapping, data validation, and complex transaction logic, leading to slow development and brittle code. StatelyDB uses DynamoDB's scalable foundation but provides a high-level, developer-friendly abstraction that eliminates this unnecessary work.
DynamoDB is a powerful storage engine, but its raw API forces immense complexity onto your application layer. Developers must manually handle object mapping, data validation, and complex transaction logic, leading to slow development and brittle code. StatelyDB uses DynamoDB's scalable foundation but provides a high-level, developer-friendly abstraction that eliminates this unnecessary work.
MongoDB offers a more flexible developer experience than DynamoDB, but it lacks integrated schema tools. This pushes the burden of schema management and data validation onto the application, often through third-party Object-Document Mappers (ODMs). Crucially, MongoDB provides no native tools for managing schema evolution or ensuring backwards compatibility, forcing teams to slow down and manually manage the risk of every change. StatelyDB combines the flexibility of a document model with the safety and power of a first-class schema system.
MongoDB offers a more flexible developer experience than DynamoDB, but it lacks integrated schema tools. This pushes the burden of schema management and data validation onto the application, often through third-party Object-Document Mappers (ODMs). Crucially, MongoDB provides no native tools for managing schema evolution or ensuring backwards compatibility, forcing teams to slow down and manually manage the risk of every change. StatelyDB combines the flexibility of a document model with the safety and power of a first-class schema system.
DynamoDB is a powerful storage engine, but its raw API forces immense complexity onto your application layer. Developers must manually handle object mapping, data validation, and complex transaction logic, leading to slow development and brittle code. StatelyDB uses DynamoDB's scalable foundation but provides a high-level, developer-friendly abstraction that eliminates this unnecessary work.
MongoDB offers a more flexible developer experience than DynamoDB, but it lacks integrated schema tools. This pushes the burden of schema management and data validation onto the application, often through third-party Object-Document Mappers (ODMs). Crucially, MongoDB provides no native tools for managing schema evolution or ensuring backwards compatibility, forcing teams to slow down and manually manage the risk of every change. StatelyDB combines the flexibility of a document model with the safety and power of a first-class schema system.
Get hands-on with our SDK and experience a database designed for developer productivity.
Dive deeper into our API and see real-world code examples for your preferred language.