npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

@voiddb/orm

v1.2.3

Published

Official TypeScript ORM for VoidDB - type-safe document store client

Readme

Why use it

@voiddb/orm is built for the same workflow that makes Prisma productive:

  • one command to scaffold local schema/config folders
  • live schema pull and push from a running database
  • short migration commands
  • generated TypeScript types
  • typed query builder with raw JSON export when you need it
  • a client that can boot directly from environment variables
  • direct file upload into Blob fields without hand-writing S3 refs

It stays close to the VoidDB HTTP API, so debugging stays simple.

Install

npm install @voiddb/orm

or

bun add @voiddb/orm

Quick start

import { VoidClient, query } from "@voiddb/orm";

type User = {
  _id: string;
  name: string;
  age: number;
  active: boolean;
};

const client = VoidClient.fromEnv();
await client.login(process.env.VOIDDB_USERNAME!, process.env.VOIDDB_PASSWORD!);

const users = client.db("app").collection<User>("users");

const id = await users.insert({
  name: "Alice",
  age: 30,
  active: true,
});

const rows = await users.find(
  query()
    .where("age", "gte", 18)
    .where("active", "eq", true)
    .orderBy("name")
    .limit(25)
);

console.log(query().where("active", "eq", true).json());
console.log(rows.json());

await users.patch(id, { age: 31 });
await users.delete(id);

Blob fields and file uploads

Blob is a first-class schema type. The ORM can upload a file directly into a document field:

import { VoidClient } from "@voiddb/orm";
import type { BlobRef } from "@voiddb/orm";

type Asset = {
  _id: string;
  title: string;
  original?: BlobRef;
};

const client = VoidClient.fromEnv();
await client.login(process.env.VOIDDB_USERNAME!, process.env.VOIDDB_PASSWORD!);

const assets = client.db("media").collection<Asset>("assets");

const ref = await assets.uploadFile(
  "asset-123",
  "original",
  new TextEncoder().encode("hello voiddb"),
  {
    filename: "hello.txt",
    contentType: "text/plain",
  }
);

console.log(ref._blob_url);
console.log(assets.blobUrl(ref));

To delete the file again:

await assets.deleteFile("asset-123", "original");

Zero-config project layout

Initialize a project once:

npx --package=@voiddb/orm vdb init

That creates:

.env.example
.voiddb/
  config.json
  schema/
    app.schema
  generated/
    voiddb.generated.d.ts
    index.d.ts
    index.js
  migrations/

The CLI automatically reads:

  • .env
  • .env.local
  • .voiddb/.env
  • .voiddb/config.json

By default it expects:

  • VOIDDB_URL
  • VOIDDB_TOKEN
  • VOIDDB_USERNAME
  • VOIDDB_PASSWORD

New .schema format

The default schema format is grouped by database:

datasource db {
  provider = "voiddb"
  url      = env("VOIDDB_URL")
}

generator client {
  provider = "voiddb-client-js"
  output   = "../generated"
}

database {
  name = "app"

  model User {
    id String @id
    email String @unique
    name String
    createdAt DateTime @default(now())
    updatedAt DateTime @default(now()) @updatedAt
    @@map("users")
  }
}

Older top-level model ... syntax is still parsed for compatibility.

Short CLI commands

After install, the short bin is vdb.

Local project:

npm install -D @voiddb/orm
npx vdb init
npx vdb pull
npx vdb push
npx vdb gen
npx vdb dev --name add_users
npx vdb status
npx vdb deploy

Without installing first:

npx --package=@voiddb/orm vdb init
npx --package=@voiddb/orm vdb pull
bunx --package @voiddb/orm vdb dev --name add_users

The long forms still work too:

npx --package=@voiddb/orm voiddb-orm schema pull
npx --package=@voiddb/orm voiddb-orm migrate status

Pull, push, and migrate

With .env in the project root, commands no longer need repeated URL or auth flags:

VOIDDB_URL=https://db.lowkey.su
VOIDDB_USERNAME=admin
VOIDDB_PASSWORD=your-password

Then:

npx vdb pull
npx vdb push
npx vdb dev --name add_status
npx vdb status

Type generation runs automatically after pull, push, dev, and deploy unless you pass --no-generate.

Schema sync is scoped to the databases explicitly present in the schema file. Databases not mentioned in the schema are not changed, dropped, or rewritten.

Generated types

Generated declarations live in:

.voiddb/generated/voiddb.generated.d.ts
.voiddb/generated/index.d.ts

So you can import from the folder instead of the generated filename:

import type {
  User,
  UserCreateInput,
  VoidDbGeneratedCollections,
  VoidDbGeneratedCollectionsByPath,
  VoidDbGeneratedDatabases,
} from "./.voiddb/generated";

Use the generated maps like this:

type ExactLowkeyUser = VoidDbGeneratedDatabases["lowkey"]["users"];
type AnyUsersCollection = VoidDbGeneratedCollections["users"];
type ExactPath = VoidDbGeneratedCollectionsByPath["lowkey/users"];

const users = client
  .database("lowkey")
  .collection<VoidDbGeneratedDatabases["lowkey"]["users"]>("users");

You can also regenerate explicitly:

npx vdb gen

Query builder

const built = query()
  .where("age", "gte", 18)
  .orderBy("createdAt", "desc")
  .limit(10);

const rows = await users.find(built);
const rawQuery = built.json();
const first = rows.first();
const plainRows = rows.toArray();
const jsonRows = rows.json();

You can also use a shorthand object filter for equality checks:

const admins = await users.find({
  where: {
    isAdmin: true,
  },
});

If you prefer a more explicit method name, .query() is an alias of .find():

const admins = await users.query({
  where: {
    isAdmin: true,
  },
});

Relation includes

const result = await client
  .db("app")
  .collection("users")
  .findWithRelations<{
    profile: { _id: string; bio: string };
  }>(
    query()
      .where("_id", "eq", "user-1")
      .include({
        as: "profile",
        relation: "many_to_one",
        target_col: "profiles",
        local_key: "profile_id",
        foreign_key: "_id",
      })
  );

Cache API

await client.cache.set("session:alice", { loggedIn: true }, 3600);
const session = await client.cache.get<{ loggedIn: boolean }>("session:alice");
await client.cache.delete("session:alice");

Links

License

MIT