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 🙏

© 2025 – Pkg Stats / Ryan Hefner

dormroom

v1.0.1

Published

[![janwilmake/dorm context](https://badge.forgithub.com/janwilmake/dorm/tree/main/template.ts)](https://uithub.com/janwilmake/dorm/tree/main/template.ts) [![](https://badge.xymake.com/janwilmake/status/1915415919335006432)](https://xymake.com/janwilmake/s

Readme

🛏️ DORM - Unlimited SQLite DBs Directly In Your Worker

janwilmake/dorm context

DORM makes building multi-tenant applications on Cloudflare ridiculously easy by letting you:

  1. Create unlimited SQLite DBs on the fly (up to 10GB each)
  2. Query them directly from anywhere in your worker (not just inside DOs)
  3. Explore and manage your data with built-in Outerbase integration
  4. Migrate once, everywhere with built-in JIT migration-support

Perfect for SaaS applications, user profiles, rate limiting, or any case where you need isolated data stores that are lightning fast at the edge.

Demo app: https://dorm.wilmake.com | Announcement post | v1 announcement post

⚡ Key Benefits vs Alternatives

| Feature | Vanilla DOs | DORM 🛏️ | D1 | Turso | | -------------------------------------------------------- | ------------------- | ----------------------- | ----------- | ------------------- | | Multi-tenant | ✅ Unlimited | ✅ Unlimited | ❌ One DB | Pricey | | Run code where your DB is(Never >1 round-trip) | ✅ | ✅ | ❌ | ❌ | | Query from worker | ❌ Only in DO | ✅ | ✅ | ✅ | | Data Explorer | ❌ | ✅ Outerbase | ✅ | ✅ | | Migrations | ❌ | ✅ | ✅ | ✅ | | Edge Performance | Closest to user | Closest to user | Global edge | Global edge | | Developer Experience | ❌ Verbose, complex | ✅ Clean, low verbosity | ✅ Good | Good, not CF native |

See Turso vs DORM and DORM vs D1 for a more in-depth comparison with these alternatives. Also, see the pricing comparison here

🚀 Quick Start

Check out the live demo showing multi-tenant capabilities.

npm i dormroom

DORM is built atop of modular primitives called 'Power Objects'. Check https://itscooldo.com for more information!

| Summary | Prompt it | | -------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | Working example/template on how to use this | | | Entire implementation of the package | | | Create a customized guide for a particular usecase | | | General information | |

View your data with Outerbase Studio:

Local Development:

  1. Install: https://github.com/outerbase/studio
  2. Create starbase connecting to: http://localhost:8787/{tenant}/api/db (or your port, your prefix)

Production: Use https://studio.outerbase.com

🔥 Top Use Cases

1. Multi-tenant SaaS applications

Create a separate database for each customer/organization:

const client = createClient({
  doNamespace: env.DORM_NAMESPACE,
  ctx: ctx,
  configs: [
    { name: `tenant:${tenantId}` }, // One DB per tenant
    { name: "aggregate" }, // Optional: Mirror to aggregate DB
  ],
});

2. Global user profiles with edge latency

Store user data closest to where they access it:

const client = createClient({
  doNamespace: env.DORM_NAMESPACE,
  ctx: ctx,
  configs: [
    { name: `user:${userId}` }, // One DB per user
  ],
});

3. Data aggregation with mirroring

Mirror tenant operations to a central database for analytics:

const client = createClient({
  doNamespace: env.DORM_NAMESPACE,
  ctx: ctx,
  configs: [
    { name: `tenant:${tenantId}` }, // Main DB
    { name: "aggregate" }, // Mirror operations to aggregate DB
  ],
});

When creating mirrors, be wary of naming collisions and database size:

  • Auto increment drift: when you use auto-increment and unique IDs (or columns in general), you may run into the issue that the value will be different in the aggregate DB. This causes things to drift apart! To prevent this issue I recommend not using auto increment or random in the query, and generate unique IDs beforehand when doing a query, so the data remains the same.

  • Size: You have max 10GB. When you chose to use an aggregate DB of some sort, ensure to keep this in mind.

✨ Key Features

  • Direct SQL anywhere: No need to write DO handler code - query from your worker
  • Outerbase integration: Explore and manage your data with built-in tools
  • JSON Schema support: Define tables using JSON Schema with automatic SQL translation
  • JIT Migrations: Migrations are applied when needed, just once, right before a DO gets accessed (via @Migratable)
  • Data mirroring: Mirror operations to aggregate databases for analytics
  • Low verbosity: Clean API that hides Durable Object complexity

🛠️ Advanced Features

Setting up your Durable Object with Migrations

import { Queryable, Migratable } from "dormroom";

@Migratable({
  migrations: {
    1: [`CREATE TABLE IF NOT EXISTS users (id TEXT PRIMARY KEY, name TEXT)`],
    2: [`ALTER TABLE users ADD COLUMN email TEXT`],
  },
})
@Queryable()
export class DORM extends DurableObject {
  sql: SqlStorage;

  constructor(state: DurableObjectState, env: any) {
    super(state, env);
    this.sql = state.storage.sql;
  }

  getDatabaseSize() {
    return this.sql.databaseSize;
  }
}

JSONSchema to SQL Conversion

import { jsonSchemaToSql, TableSchema } from "dormroom";

const userSchema: TableSchema = {
  $id: "users",
  properties: {
    id: { type: "string", "x-dorm-primary-key": true },
    name: { type: "string", maxLength: 100 },
    email: { type: "string", "x-dorm-unique": true },
  },
  required: ["id", "name"],
};

const sqlStatements = jsonSchemaToSql(userSchema);

REST API for Data Access

// Access your database via REST API
const studioResponse = await client.studio(request);

if (studioResponse) {
  return studioRepsonse;
}

Extending DORM

You can extend DORM with your own DO implementation to circumvent limitations doing single queries remotely gives you.

@Migratable({
  migrations: {
    1: [`CREATE TABLE IF NOT EXISTS users (id TEXT PRIMARY KEY, name TEXT)`],
  },
})
@Streamable()
export class YourDO extends DurableObject {
  sql: SqlStorage;

  constructor(state: DurableObjectState, env: any) {
    super(state, env);
    this.sql = state.storage.sql;
  }

  async myExtendedFunction() {
    // Multiple queries in one transaction
    const users = await this.sql.exec("SELECT * FROM users").toArray();
    const count = await this.sql
      .exec("SELECT COUNT(*) as count FROM users")
      .one();
    return { users, count };
  }

  getDatabaseSize() {
    return this.sql.databaseSize;
  }
}

This allows:

  • Doing a multitude of SQL queries inside of your DO from a single API call
  • Using alarms and other features
  • Complex transactions

📊 Performance & Limitations

  • Nearly zero overhead: Thin abstraction over DO's SQLite
  • Edge-localized: Data stored closest to where it's accessed
  • Up to 10GB per DB: Sufficient for most application needs
  • ❓ Localhost isn't easily accessible YET in https://studio.outerbase.com so you need to deploy first, use a tunnel, or run the outerbase client on localhost.

🔗 Links & Resources

🚧 Status: Beta

DORM is currently in beta. API may change!

Deploy to Cloudflare Workers