Simple by Design, Powerful by Default

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.

Ship Features, Not Database Plumbing

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 error
No items found.

This 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.

Ship Features, Not Database Plumbing

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 error
No items found.

Ship Features, Not Database Plumbing

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 error

This 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.

A Developer Experience Built for Velocity

Our entire platform is designed around a streamlined developer workflow that eliminates friction and accelerates feature delivery.

1
Type-Safe, Generated Code

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.

1
Type-Safe, Generated Code

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.

2
A Clean, Minimalist API

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:

  • Put: Creates or replaces an item.
  • Get: Retrieves an item by its key.
  • Delete: Removes an item.
  • List: Fetches a collection of items within the same group.
  • Sync: Efficiently gets only the changes to a list since the last time you checked.
  • Transaction: Executes a series of read and write operations atomically.

This streamlined API eliminates the steep learning curve and performance surprises common with other databases.

2
A Clean, Minimalist API

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:

  • Put: Creates or replaces an item.
  • Get: Retrieves an item by its key.
  • Delete: Removes an item.
  • List: Fetches a collection of items within the same group.
  • Sync: Efficiently gets only the changes to a list since the last time you checked.
  • Transaction: Executes a series of read and write operations atomically.

This streamlined API eliminates the steep learning curve and performance surprises common with other databases.

3
Zero-Downtime Schema Migrations

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.

3
Zero-Downtime Schema Migrations

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.

A Developer Experience Built for Velocity

Our entire platform is designed around a streamlined developer workflow that eliminates friction and accelerates feature delivery.

Type-Safe, Generated Code

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.

A Clean, Minimalist API

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:

  • Put: Creates or replaces an item.
  • Get: Retrieves an item by its key.
  • Delete: Removes an item.
  • List: Fetches a collection of items within the same group.
  • Sync: Efficiently gets only the changes to a list since the last time you checked.
  • Transaction: Executes a series of read and write operations atomically.

This streamlined API eliminates the steep learning curve and performance surprises common with other databases.

Zero-Downtime Schema Migrations

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.

A Developer Experience Built for Velocity

Our entire platform is designed around a streamlined developer workflow that eliminates friction and accelerates feature delivery.

Complexity vs. Clarity

1
StatelyDB vs. DynamoDB

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.

1
StatelyDB vs. DynamoDB

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.

2
StatelyDB vs. MongoDB

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.

2
StatelyDB vs. MongoDB

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.

Complexity vs. Clarity

StatelyDB vs. DynamoDB

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.

StatelyDB vs. MongoDB

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.

Complexity vs. Clarity

No items found.

No items found.

No items found.

Start Building for Free

Get hands-on with our SDK and experience a database designed for developer productivity.

Read the Docs

Dive deeper into our API and see real-world code examples for your preferred language.