Skip to main content

Introduction

Dynatable is a type-safe, functional TypeScript library for Amazon DynamoDB. Built with modern TypeScript features and functional programming principles, it provides a robust and developer-friendly way to work with DynamoDB.

Why Dynatable?

DynamoDB is powerful but has a steep learning curve. Dynatable simplifies DynamoDB development while maintaining full type safety and leveraging functional programming patterns.

Key Features

Type-Safe by Design

Complete TypeScript type inference from your schema definitions. Get autocomplete and compile-time error detection throughout your entire codebase.

const user = await table.entities.User.get({ username: 'alice' }).execute();
// ^? User: { username: string, name: string, email: string, ... }

Functional & Immutable

Immutable builder API that prevents side effects and makes your code more predictable and easier to reason about.

const baseQuery = table.entities.Post.query().where((attr, op) => op.eq(attr.username, 'alice'));

// Create variations without mutating the original
const recentPosts = baseQuery.limit(10).scanIndexForward(false);
const allPosts = baseQuery.execute();

Runtime Validation

Automatic Zod validation enforces your declared types and required fields at runtime:

await table.entities.User.put({
username: 'alice',
age: '25', // Error: Expected number, got string
}).execute();

For richer rules (email format, length, regex…), validate inputs with your own Zod schemas before calling .put() / .update().

Developer Experience First

  • Automatic timestamps (createdAt, updatedAt)
  • Built-in pagination support
  • Auto-generated IDs (ULID, UUID)
  • Single-table design patterns
  • Comprehensive transaction support
  • Efficient batch operations

Architecture Overview

Dynatable follows a layered architecture:

┌─────────────────────────────────────┐
│ Schema Definition │
│ (Define your data models) │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│ Table API │
│ (Main entry point) │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│ Entity APIs │
│ (User, Post, Comment, etc.) │
└─────────────────────────────────────┘

┌─────────────────────────────────────┐
│ Operation Builders │
│ (Get, Put, Query, Update, etc.) │
└─────────────────────────────────────┘

Core Concepts

Before diving into Dynatable, it's helpful to understand a few core concepts:

Entities

Entities represent your data models (e.g., User, Post, Comment). Each entity has:

  • A unique key structure (partition key and optionally sort key)
  • Defined attributes with types and constraints
  • Optional automatic behaviors (timestamps, ID generation)

Builders

All operations use immutable builders that allow you to chain methods to construct your query or mutation:

const posts = await table.entities.Post.query()
.where((attr, op) => op.eq(attr.username, 'alice'))
.limit(20)
.scanIndexForward(false)
.execute();

Type Inference

Your schema is the source of truth. Types flow automatically from your schema definition to all operations:

const schema = {
models: {
User: {
attributes: {
username: { type: String, required: true },
email: { type: String, required: true },
},
},
},
} as const; // ← as const is important for type inference

// TypeScript knows exactly what fields exist
const user = await table.entities.User.get({ username: 'alice' }).execute();
console.log(user.email); // ✅ Type-safe
console.log(user.invalid); // ❌ TypeScript error

What's Next?

Ready to get started? Here's your learning path:

  1. Getting Started - Install and set up Dynatable
  2. Data Modeling - Learn how to design your schema
  3. Single Table Design - Master single-table patterns
  4. Queries - Read and filter your data
  5. Mutations - Create, update, and delete operations
  6. Examples - See real-world examples

Community & Support

License

MIT © 2024 Dynatable