MonkeyDB

A key-value database with automatic multi-tenancy, typed queries, and sparse indexing — without touching partition keys or internal index slots.

Collection Creation

Create a typed collection with optional indexes. Collections are registered automatically on first use.

typescript
// Simple indexes
const users = db.collection<User>('users', { indexes: ['email', 'role'] })

// Compound index (hash + range key)
const orders = db.collection<Order>('orders', {
  indexes: [
    'status',
    { name: 'byCustomer', hashKey: 'customerId', rangeKey: 'createdAt' },
  ],
})

// Custom primary key
const events = db.collection<Event>('events', {
  key: { hashKey: 'streamId', rangeKey: 'sequence' },
})

// With vector search
const articles = db.collection<Article>('articles', {
  search: { fields: ['title', 'body'] },
})

Declared indexes map to internal GSI slots. Queries against indexed fields are fast (GSI lookup). The number of indexes per collection is limited by your plan tier.

CRUD Operations

save()

Upsert one or many items. Auto-chunks batches larger than 25 items.

typescript
// Single item
await users.save({ id: 'user_01', email: 'jerry@monkey.io', role: 'admin' })

// Batch — auto-chunks at 25
await users.save([
  { id: 'user_01', email: 'jerry@monkey.io', role: 'admin' },
  { id: 'user_02', email: 'george@monkey.io', role: 'member' },
])

findOne()

Fetch a single item by ID. Sub-10ms latency.

typescript
const jerry = await users.findOne('user_01')

find()

Batch fetch by multiple IDs. Auto-chunks requests exceeding 100 keys.

typescript
const batch = await users.find(['user_01', 'user_02', 'user_03'])

remove()

Hard delete an item by ID.

typescript
await users.remove('user_01')

Query Interface

Queries use hashKey for fast indexed lookups and filter for post-read filtering.

typescript
interface QueryOptions {
  hashKey: string | number        // Required — the indexed field value
  rangeKey?: string | number      // Optional range key value
  rangeKeyOp?: '=' | 'begins_with' | '<' | '<=' | '>' | '>='
  index?: string                  // Index name (omit for primary key)
  filter?: Record<string, { [op: string]: any }>
  limit?: number                  // Max 100, server-enforced
  reverse?: boolean               // Newest first
  cursor?: string                 // Pagination cursor
}

Fast query (indexed)

typescript
// Hits GSI directly — fast and efficient
await orders.query({ hashKey: 'paid', index: 'status' })

Combined query

typescript
// GSI lookup + post-read filter
await orders.query({
  hashKey: 'paid',
  index: 'status',
  filter: { amount: { '>': 50 } },
  limit: 20,
  reverse: true,
})
Important: Queries without a hashKey are rejected with 400 Bad Request. This prevents accidental table scans.

Pagination

All queries return a cursor for pagination. Pass it to the next query to get the next page.

typescript
let cursor: string | undefined
do {
  const result = await users.query({
    hashKey: 'admin',
    index: 'role',
    limit: 20,
    cursor,
  })
  processItems(result.items)
  cursor = result.cursor
} while (cursor)

Enable semantic search on any collection. MonkeyHub automatically generates embeddings using OpenAI text-embedding-3-small and stores vectors in S3.

typescript
// Enable at collection creation
const articles = db.collection<Article>('articles', {
  search: { fields: ['title', 'body'] },
})

// Save items — embeddings are generated automatically
await articles.save({
  id: 'post_01',
  title: 'Getting started with MonkeyHub',
  body: 'MonkeyHub is a backend-as-a-service...',
})

// Search by natural language
const results = await articles.search({
  text: 'how to set up a database',
  topK: 10,
})

// results.items = [{ item: { id, title, body }, score: 0.92, distance: 0.08 }, ...]
Note: Collections with search enabled cannot use range keys. topK is capped at 50 (Baby Monkey), 75 (Chimp), or 100 (Mandrill/Silverback).

Limits

Indexes per plan

Baby Monkey (Free)Chimp ($19/mo)Mandrill ($49/mo)Silverback ($199/mo)
Indexes / collection1235
Max write cost2x base3x base4x base6x base

Other limits

LimitValue
Max item size400 KB
Max query limit100 (server-enforced)
Max batch save25 items per call (SDK auto-chunks larger batches)
Max batch find100 keys per call (SDK auto-chunks larger batches)