Quick Start

Get up and running with Turbine in just a few minutes.

Prerequisites

Installation

Install Turbine and Zod:

npm install dynamodb-turbine zod

Step 1: Define Your Table

First, define your DynamoDB table structure. Turbine needs to know about your table's indexes:

import { defineTable } from "dynamodb-turbine";

const table = defineTable({
  name: "my-app-table",
  indexes: {
    table: { hashKey: "pk", rangeKey: "sk" },
    gsi1: { hashKey: "type", rangeKey: "createdAt" },
  },
});

The table index is your primary key. Additional indexes (like gsi1) are Global Secondary Indexes.

Step 2: Define an Entity

Create an entity with a Zod schema for validation:

import { defineEntity } from "dynamodb-turbine";
import { z } from "zod";

const users = defineEntity({
  table,
  schema: z.object({
    id: z.string(),
    email: z.string().email(),
    name: z.string(),
    role: z.enum(["user", "admin"]).default("user"),
    createdAt: z.string().datetime().default(() => new Date().toISOString()),
  }),
  keys: {
    type: () => "user",
    pk: (user) => ["user", user.id],
    sk: (user) => ["profile", user.email],
  },
});

Key functions receive the entity data and return values that become DynamoDB attributes. Arrays are automatically joined with #.

Step 3: Create Items

Use put() to create new items:

const user = await users.put({
  id: "user-123",
  email: "alice@example.com",
  name: "Alice",
});

console.log(user.id);        // "user-123"
console.log(user.role);      // "user" (default value)
console.log(user.createdAt); // "2024-01-15T10:30:00.000Z"

Step 4: Fetch Items

Use get() to fetch a single item by its keys:

const user = await users.get({
  pk: ["user", "user-123"],
  sk: ["profile", "alice@example.com"],
});

if (user) {
  console.log(user.name); // "Alice"
}

Step 5: Update Items

Update items using the entity method or the instance method:

// Entity method - requires keys
await users.update(
  { pk: ["user", "user-123"], sk: ["profile", "alice@example.com"] },
  { name: "Alice Smith" }
);

// Instance method - more convenient
const user = await users.get({ pk: ["user", "user-123"], sk: ["profile", "alice@example.com"] });
await user?.update({ name: "Alice Smith" });

Step 6: Query Items

Query for multiple items using indexes:

// Query all users created in 2024
const users2024 = await users.queryAll({
  index: "gsi1",
  type: "user",
  createdAt: { beginsWith: "2024" },
});

// Query with pagination
const page1 = await users.query(
  { index: "gsi1", type: "user" },
  { Limit: 10 }
);

if (page1.next) {
  const page2 = await page1.next();
}

Step 7: Delete Items

Remove items with delete():

await users.delete({
  pk: ["user", "user-123"],
  sk: ["profile", "alice@example.com"],
});

Complete Example

Here's a complete working example:

import { defineTable, defineEntity } from "dynamodb-turbine";
import { z } from "zod";

// Table definition
const table = defineTable({
  name: process.env.TABLE_NAME!,
  indexes: {
    table: { hashKey: "pk", rangeKey: "sk" },
    gsi1: { hashKey: "type", rangeKey: "createdAt" },
  },
});

// User entity
const users = defineEntity({
  table,
  schema: z.object({
    id: z.string(),
    email: z.string().email(),
    name: z.string(),
    createdAt: z.string().datetime().default(() => new Date().toISOString()),
  }),
  keys: {
    type: () => "user",
    pk: (u) => ["user", u.id],
    sk: (u) => ["profile", u.email],
  },
});

// Usage
async function main() {
  // Create
  const user = await users.put({
    id: "123",
    email: "alice@example.com",
    name: "Alice",
  });

  // Read
  const fetched = await users.get({
    pk: ["user", "123"],
    sk: ["profile", "alice@example.com"],
  });

  // Update
  await fetched?.update({ name: "Alice Smith" });

  // Query
  const allUsers = await users.queryAll({
    index: "gsi1",
    type: "user",
  });

  // Delete
  await users.delete({
    pk: ["user", "123"],
    sk: ["profile", "alice@example.com"],
  });
}

Next Steps