watermelondb
v1.1.0
Published
In-memory reactive data SDK for Node.js and web projects with schema validation and transactional writes.
Downloads
304
Maintainers
Readme
watermelondb
watermelondb is a lightweight in-memory data SDK for Node.js and browser-adjacent runtimes. It is aimed at developers who want a structured local data layer with schema validation, transactional writes, and reactive events without bringing in a full database service.
This package is intentionally organized like an SDK rather than a demo:
- schema parsing lives in dedicated modules
- collections and transactions are reusable components
- change events can be consumed by higher-level application code
- dependencies are chosen to make the package practical in real projects
What developers get
zod-validated schemaseventemitter3-based change subscriptionsnanoid-based record IDs- transactional
write()and groupedbatch()operations - reusable collection helpers such as
upsert,findMany,first, andexists
Installation
npm install watermelondbPackage structure
watermelondb/
├── index.js
├── src/
│ ├── collection.js
│ ├── database.js
│ ├── index.js
│ ├── schema.js
│ └── utils.js
└── test.jsGood use cases
- internal tools
- local-first prototypes
- test fixtures and labs
- sync staging layers
- small embedded stores inside larger SDKs
Quick start
const { Database, appSchema, tableSchema } = require('watermelondb');
const schema = appSchema({
version: 1,
tables: [
tableSchema({
name: 'posts',
columns: [
{ name: 'title', type: 'string' },
{ name: 'published', type: 'boolean', default: false },
{ name: 'tags', type: 'array', default: () => [] },
],
}),
tableSchema({
name: 'comments',
columns: [
{ name: 'postId', type: 'string', isIndexed: true },
{ name: 'body', type: 'string' },
],
}),
],
});
const db = new Database({ schema });
await db.write(async () => {
const posts = db.collection('posts');
const comments = db.collection('comments');
const post = posts.create({
title: 'Hello world',
tags: ['intro'],
});
comments.create({
postId: post.id,
body: 'Great post',
});
});
const publishedPosts = await db.read(() =>
db.collection('posts').query({ published: true })
);
console.log(publishedPosts);Reactive subscriptions
const unsubscribe = db.collection('posts').subscribe((event) => {
console.log(event.type, event.record);
});
await db.write(async () => {
db.collection('posts').create({ title: 'Realtime row' });
});
unsubscribe();Transaction and batch behavior
Writes roll back automatically when the callback throws:
await db.write(async () => {
db.collection('posts').create({ title: 'Temporary row' });
throw new Error('rollback');
});Batch operations help group related changes:
await db.batch([
() => db.collection('posts').create({ title: 'One' }),
() => db.collection('posts').create({ title: 'Two' }),
() => db.collection('posts').upsert('posts_custom', { title: 'Pinned' }),
]);Collection workflow example
const posts = db.collection('posts');
const created = posts.create({ title: 'New post' });
const updated = posts.update(created.id, { published: true });
const same = posts.find(created.id);
const many = posts.findMany([created.id]);
const firstPublished = posts.first({ published: true });
const exists = posts.exists((row) => row.title.startsWith('New'));
const total = posts.count();
const allPosts = posts.all();
const exported = posts.toJSON();API reference
appSchema({ version, tables })
Creates and validates the database schema.
tableSchema({ name, columns })
Creates and validates a table definition.
Supported column types:
stringnumberbooleanobjectarraydateany
Column fields:
| Field | Description |
| --- | --- |
| name | Column name |
| type | Column type |
| isIndexed | Metadata flag for higher-level tooling |
| default | Static value or function returning a default value |
new Database({ schema })
Main methods:
collection(name)read(callback)write(callback)batch(operations)export()
Collection
Methods:
create(fields)upsert(id, fields)find(id)findMany(ids)all()first(predicateOrCriteria?)exists(predicateOrCriteria?)query(predicateOrCriteria?)update(id, fields)delete(id)count(predicateOrCriteria?)clear()toJSON()subscribe(listener)
predicateOrCriteria can be:
- a predicate function such as
(row) => row.published - a plain object such as
{ published: true }
Integration example
This package works well behind a higher-level project SDK:
class ProjectStore {
constructor(db) {
this.db = db;
}
saveProject(project) {
return this.db.write(() =>
this.db.collection('projects').upsert(project.id, project)
);
}
listProjects() {
return this.db.read(() => this.db.collection('projects').all());
}
}License
This package is licensed under the MIT License. See LICENSE.
