Melon-dbMelon-db
Setup

Models

TypeScript record types for collections — no ORM classes required.

Melon-db does not use decorator-based model classes like WatermelonDB. Collections are defined in schema metadata; your app uses plain TypeScript interfaces (or generated types) for record shapes.

Pattern

Define one interface per collection next to your schema:

import { type DatabaseSchemaDefinition, createMelonSchema } from '@melon-db/db';

export const taskSchemaDefinition: DatabaseSchemaDefinition = {
  version: 1,
  collections: {
    tasks: {
      name: 'tasks',
      primaryKey: 'id',
      fields: {
        id: { kind: 'string' },
        title: { kind: 'string' },
        status: { kind: 'string', indexed: true },
        priority: { kind: 'number' },
        updatedAt: { kind: 'date' },
      },
    },
  },
};

export const taskSchema = createMelonSchema(taskSchemaDefinition);

export interface Task {
  id: string;
  title: string;
  status: string;
  priority: number;
  updatedAt: Date;
}

Use Task with collection methods and hooks:

const task = await db.collection('tasks').findById('1') as Task | null;

Typing collections

MelonCollection is generic over the record shape when you pass a type argument through your own wrappers. Hooks accept a generic:

import { useQuery } from '@melon-db/db-react';

const tasks = useQuery<Task>(openTasksAst);

The query builder uses the same pattern:

import { createQueryFactory } from '@melon-db/db-query';

createQueryFactory(taskSchema).from<Task>('tasks').where('status', 'eq', 'open');

Inserts and updates

insert and update accept partial objects (InsertInput / UpdateInput). You only need to supply required fields on insert:

await db.write(async (tx) => {
  await tx.collection('tasks').insert({
    id: crypto.randomUUID(),
    title: 'Ship docs',
    status: 'open',
    priority: 2,
    updatedAt: new Date(),
  });
});

Relations on records

When you include a belongsTo relation, the adapter attaches nested objects on each row:

interface TaskWithProject extends Task {
  project?: { id: string; name: string } | null;
}

There is no automatic inverse hasMany loader in v1 — fetch child rows with a separate query filtered by foreign key.

Prisma-style codegen (optional)

@melon-db/db-prisma can import a Prisma schema and generate model interfaces plus a local client facade. The runtime engine remains @melon-db/db; generated types are a DX layer only.

  • Schema — field and relation definitions
  • CRUD — collection read/write APIs
  • React hooks — useQuery<Task>(...)