Getting Started with ctrodb: A Client-Side Database for Modern Web Apps
Learn how to set up ctrodb, define schemas, and perform CRUD operations in the browser and Node.js.
ctrodb is a zero-dependency, reactive, client-side database that works in the browser and Node.js. It gives you a MongoDB-like API with full TypeScript support, IndexedDB persistence, and signal-based reactivity — all without a server.
In this guide, you'll learn how to install ctrodb, define your first schema, and perform create, read, update, and delete operations.
Installation
Install ctrodb via npm:
npm install ctrodb
ctrodb has zero runtime dependencies. The package ships ESM, CJS, and IIFE formats, so it works with any bundler or directly in the browser via a <script> tag.
Creating a Database
Import the Database class and create an instance with a configuration object:
import { Database } from "ctrodb"
const db = new Database({
name: "my-app",
adapter: "memory", // or "indexeddb" for persistence
})
await db.connect()
console.log(db.isConnected) // true
The adapter option accepts "memory" for an in-memory store, "indexeddb" for browser persistence, or auto-detection (IndexedDB when available, memory fallback).
Defining a Schema
Schemas define the shape of your data, including field types, validation rules, indexes, and default values:
const schema = {
version: 1,
collections: {
users: {
fields: {
name: { type: "string", required: true },
email: { type: "string", required: true, validate: "email" },
age: { type: "number", min: 0, max: 150 },
role: { type: "string", default: "user" },
createdAt: { type: "string" },
},
indexes: [
{ field: "email", unique: true },
],
},
},
}
const db = new Database({ name: "my-app", adapter: "memory", schema })
await db.connect()
Basic CRUD Operations
Access a collection and perform operations:
const users = db.collection("users")
// Create
const user = await users.create({
name: "Alice",
email: "alice@example.com",
age: 30,
})
console.log(user.id) // auto-assigned
console.log(user.name) // "Alice"
// Read
const found = await users.get(user.id)
const allUsers = await users.getAll()
const count = await users.count()
// Update
await users.update(user.id, { age: 31 })
// Delete
await users.delete(user.id)
Upsert with put
The put method creates or updates a record by ID:
// Create new
const alice = await users.put({ name: "Alice", email: "alice@example.com" })
// Update existing
const updated = await users.put({ id: alice.id, age: 32 })
Working with Models
Every record returned from CRUD operations is a Model — a Proxy wrapper that provides transparent field access:
const user = await users.create({ name: "Bob", email: "bob@test.com" })
user.id // direct access
user.name // "Bob"
user.email // "bob@test.com"
user.toJSON() // plain object copy
// Update in-place
await user.update({ age: 25 })
// Delete in-place
await user.delete()
Models also provide helpful methods like toJSON() for serialization and update() / delete() for operating on the record directly.
Querying Data
ctrodb includes a fluent QueryBuilder for advanced queries:
// Simple equality
const admins = await users.query().where("role", "admin").fetch()
// Range queries
const adults = await users.query().where("age", ">=", 18).fetch()
// Sorting and pagination
const results = await users
.query()
.where("role", "admin")
.sort({ age: "desc" })
.limit(10)
.offset(0)
.fetch()
// Count filtered results
const total = await users.query().where("role", "admin").count()
Schema-less Mode
ctrodb also works without a schema for quick prototyping:
const db = new Database({ name: "scratch", adapter: "memory" })
await db.connect()
const items = db.collection("items")
await items.create({ name: "Widget", price: 9.99 })
await items.create({ name: "Gadget", price: 24.99 })
const all = await items.getAll()
console.log(all.length) // 2
Without a schema, no validation or indexing occurs, but all CRUD operations work normally.
Next Steps
You now have the fundamentals of ctrodb. From here, you can:
- Add persistence by switching to
adapter: "indexeddb" - Build reactive UIs with React hooks (see our React integration guide)
- Add full-text search with the FTS plugin
- Define relations between collections
- Run transactions for multi-step operations
ctrodb is designed to scale from simple prototypes to full offline-first applications — all without leaving your browser.
Related posts
Client-Side Full-Text Search with ctrodb
Build a complete search experience in the browser using ctrodb's inverted index engine, tokenizer, and search API.
PluginsExtending ctrodb with Custom Plugins
Leverage ctrodb's plugin system to add custom validation rules, lifecycle hooks, and data transformations.
TransactionsTransactions and Data Integrity in ctrodb
Ensure data consistency with ctrodb's transaction system, rollback support, and comprehensive error types.