Deposit
Deposit is a schema-driven storage library for the browser. Define typed tables, persist records to IndexedDB (structured browser database) or LocalStorage (key-value storage), and query results with a fluent builder without writing raw database calls.
Installation
sh
pnpm add @vielzeug/depositsh
npm install @vielzeug/depositsh
yarn add @vielzeug/depositQuick Start
ts
import { createLocalStorage, defineSchema } from '@vielzeug/deposit';
interface User {
id: number;
name: string;
age: number;
}
const schema = defineSchema<{ users: User }>({ users: { key: 'id' } });
const db = createLocalStorage({ dbName: 'my-app', schema });
await db.put('users', { id: 1, name: 'Alice', age: 30 });
await db.put('users', { id: 2, name: 'Bob', age: 25 });
const adults = await db.from('users').between('age', 18, 99).orderBy('name').toArray();
const alice = await db.get('users', 1);
const patched = await db.patch('users', 1, { age: 31 }); // returns merged User
for await (const user of db.from('users').orderBy('name')) {
console.log(user.name);
}Why Deposit?
Raw IndexedDB requires verbose event-based boilerplate; localStorage loses type information and offers no query capabilities.
ts
// Before — raw IndexedDB boilerplate
const req = indexedDB.open('my-app', 1);
req.onupgradeneeded = (e) => {
(e.target as IDBOpenDBRequest).result.createObjectStore('users', { keyPath: 'id' });
};
req.onsuccess = (e) => {
const db = (e.target as IDBOpenDBRequest).result;
const all = db.transaction('users', 'readonly').objectStore('users').getAll();
all.onsuccess = () => {
/* untyped, no filtering */
};
};
// After — Deposit
import { createLocalStorage, defineSchema } from '@vielzeug/deposit';
const schema = defineSchema<{ users: User }>({ users: { key: 'id', indexes: ['age'] } });
const db = createLocalStorage({ dbName: 'my-app', schema });
await db.put('users', { id: 1, name: 'Alice', age: 30 });
const adults = await db.from('users').between('age', 18, 99).orderBy('name').toArray();| Feature | Deposit | Dexie.js | idb |
|---|---|---|---|
| Bundle size | 3.4 KB | ~32 kB | ~1.5 kB |
| LocalStorage adapter | ✅ Built-in | ❌ | ❌ |
| Query builder | ✅ Fluent | ✅ | ❌ |
| TTL support | ✅ Built-in | ❌ | ❌ |
| Typed schema | ✅ | ⚠️ Manual | ❌ |
| Transactions | ✅ (IndexedDB) | ✅ | ✅ |
| Zero dependencies | ✅ | ✅ | ✅ |
Use Deposit when you want typed, queryable browser storage across both localStorage and IndexedDB through one consistent API.
Consider Dexie.js if you need live queries, Dexie Cloud sync, or advanced IndexedDB hooks beyond what Deposit offers.
Features
- Two adapters —
createLocalStorage()andcreateIndexedDB()share an identicalAdapterinterface - Schema-driven —
defineSchema()types every table, key, and query result; or pass inline with a type parameter - Fluent query builder —
equals,between,startsWith,filter,and,or,search,contains,orderBy,limit,offset,page,map,reduce, and more for await...of—QueryBuilderimplementsAsyncIteratorfor streamed processing- TTL — per-record expiry via optional
ttlonput,putMany, andgetOrPut; use thettlhelper (.days(),.hours(),.minutes(),.seconds(),.ms()) for readable durations - Adapter-specific count semantics — localStorage returns TTL-accurate counts; IndexedDB returns native O(1) counts (expired records may still be included until eviction)
patchreturns merged record — no follow-upgetneeded after a partial updategetOr— typed non-nullable get with a fallback default valuegetMany— batch fetch by a list of keys in a single operation- Transactions — atomic multi-table writes with the full read/write method set (IndexedDB only)
- Bulk operations —
putManyanddeleteManyfor operating on multiple records at once storeField()— migration helper that encapsulates deposit's internal key-path convention- Utility types —
RecordOf<S, K>andKeyOf<S, K>for typed schema access - Lightweight — 3.4 KB gzipped, zero external dependencies
Compatibility
| Environment | Support |
|---|---|
| Browser | ✅ (IndexedDB/LocalStorage) |
| Node.js | ❌ (Web APIs only) |
| SSR | ❌ |
| Deno | ❌ |
Prerequisites
- Browser environment with
indexedDBand/orlocalStorageavailable. - Storage permission must be enabled in the runtime context (for example, not blocked by privacy mode).
- Define a schema up front so query/index operations stay typed.