Typed from the first call
Use collection<T>() in the SDK, keep your app code honest, and stop inventing one-off wrappers around raw database records.
Create typed collections, declare indexes once, and query by name instead of rebuilding a storage abstraction around partition keys, GSIs, and tenant safety.
One data plane across SDK, CLI workflows, dashboard views, and MCP-powered agents.
Collection Surface
const runs = monkey.collection<Run>('runs', {
indexes: [
'status',
{ name: 'byAgentDate', hashKey: 'agentId', rangeKey: 'createdAt' },
],
})
await runs.query({ index: 'status', hashKey: 'queued' })Auto-register on first use
Create the collection in code and start writing data immediately. No control plane click-path first.
Query through named indexes
Ask for status or byAgentDate. MonkeyDB handles the backing GSI translation for you.
Use the same data from agents
Collections stay available through the same org auth and MCP surface your app already uses.
Why MonkeyDB
MonkeyDB keeps the parts that make high-scale storage useful and removes the parts that usually force teams to build their own wrapper first.
Use collection<T>() in the SDK, keep your app code honest, and stop inventing one-off wrappers around raw database records.
Declare indexes once. MonkeyDB maps them onto shared sparse GSI slots so you query with index names instead of table internals.
Org and namespace isolation sit in the storage model itself, which removes a whole class of cross-tenant query mistakes.
Apps, CLI workflows, and MCP-powered agents hit the same auth, limits, and collection surface instead of parallel tooling stacks.
How It Works
The core trick is simple: MonkeyDB exposes named indexes, then maps them onto a fixed pool of sparse shared GSI slots behind the scenes.
Create a collection with named indexes like status or byAgentDate. No partition-key design workshop required.
Those named indexes are assigned to one of five shared sparse GSI slots, only when a record actually uses them.
Your app asks for index: "status" and hashKey: "queued". MonkeyDB translates the query to the right GSI path for you.
Index Mapping
runs collection
runs.query({ index: 'status', hashKey: 'queued' })Real Surface Area
These examples match the implemented SDK and CLI surface. No pseudo-API, no marketing-only syntax.
Typed collections, save(), and query() with named indexes.
import { Monkey } from '@monkeyhub/sdk'
type Run = {
id: string
agentId: string
status: 'queued' | 'running' | 'completed'
createdAt: string
prompt: string
}
const monkey = new Monkey(process.env.MONKEY_KEY!)
const runs = monkey.collection<Run>('runs', {
indexes: [
'status',
{ name: 'byAgentDate', hashKey: 'agentId', rangeKey: 'createdAt' },
],
})
await runs.save({
id: 'run_001',
agentId: 'agent_alpha',
status: 'queued',
createdAt: '2026-03-16T18:30:00.000Z',
prompt: 'Summarize incident notes from the night shift',
})
const queued = await runs.query({
index: 'status',
hashKey: 'queued',
limit: 20,
reverse: true,
})The same collection registration and query flow for scripts and CI jobs.
monkey db save runs \
--config '{"indexes":["status",{"name":"byAgentDate","hashKey":"agentId","rangeKey":"createdAt"}]}' \
--input '{"id":"run_001","agentId":"agent_alpha","status":"queued","createdAt":"2026-03-16T18:30:00.000Z","prompt":"Summarize incident notes from the night shift"}'
monkey db query runs \
--input '{"index":"status","hashKey":"queued","limit":20,"reverse":true}'Compare
MonkeyDB is for teams who want a scalable collection model without turning every new collection into an infrastructure design task.
MonkeyDB on the MonkeyHub data plane
Sign up if you want the shortest path to a real org, API keys, and a working collection surface. Or go straight to the quickstart if you want to inspect the implementation details first.