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

@scratchyjs/drizzle

v26.3.22-1774223623833

Published

Database layer for the Scratchy framework — Drizzle ORM helpers, connection pooling, schema namespace helpers, column helpers, and a Fastify plugin.

Readme

@scratchyjs/drizzle

Database layer for the Scratchy framework — Drizzle ORM helpers, connection pooling, schema namespace helpers, column helpers, and a Fastify plugin.

Installation

pnpm add @scratchyjs/drizzle

Usage

Connection Pool

import { createPool } from "@scratchyjs/drizzle";

const pool = await createPool("postgresql://localhost:5432/mydb", {
  max: 50,
  min: 5,
});

The pool factory automatically:

  • Appends libpq keepalive parameters to prevent silent connection drops
  • Sets up TCP keepalive on new connections
  • Handles pool-level errors gracefully (doesn't crash; logs when a logger is provided)
  • Verifies the connection on startup with SELECT 1

When used with the Fastify plugin (or when you pass a logger to createPool), pool and client errors are logged via that logger; without a logger, errors are still handled so they don't crash the process.

Schema Namespace

Always use a custom PostgreSQL schema instead of the default public schema:

import { createSchema } from "@scratchyjs/drizzle";

// Reads DATABASE_SCHEMA env var, or defaults to "app"
const mySchema = createSchema();

// Or use a custom name
const mySchema = createSchema("my_app");

Column Helpers

Spread the timestamps helper into every table to get consistent created_at/updated_at columns:

import { timestamps } from "@scratchyjs/drizzle/helpers";
import { text } from "drizzle-orm/pg-core";

const user = mySchema.table("user", {
  id: text().primaryKey(),
  name: text().notNull(),
  email: text().notNull().unique(),
  ...timestamps,
});

Both columns use timestamp with time zone, default to now(), and updatedAt automatically updates via $onUpdateFn(() => new Date()).

Fastify Plugin

Register the plugin to make fastify.db and fastify.pool available:

import drizzlePlugin from "@scratchyjs/drizzle/plugin";

await server.register(drizzlePlugin, {
  connectionString: process.env.DATABASE_URL,
  schemas: { mySchema, ...allTableSchemas },
});

// Now available:
// server.db  — Drizzle ORM instance
// server.pool — underlying pg.Pool

The plugin cleans up the pool automatically on server close.

Drizzle Kit Configuration

Generate a Drizzle Kit config with Scratchy defaults:

// drizzle.config.ts
import { createDrizzleConfig } from "@scratchyjs/drizzle";

export default createDrizzleConfig({
  schema: ["./src/db/my-schema.ts", "./src/db/schema"],
  connectionString: process.env.DATABASE_URL!,
});

This enforces dialect: "postgresql" and casing: "snake_case".

Prepared Statements Pattern

Prepared statements must be module-scoped (top-level), never inside functions. This ensures they are compiled once and reused across requests:

// db/queries/users.ts
import { eq, sql } from "drizzle-orm";
import { db } from "~/db/index.js";
import { user } from "~/db/schema/user.js";

// ✅ Module-scoped prepared statement — compiled once, reused everywhere
export const findUserById = db
  .select()
  .from(user)
  .where(eq(user.id, sql.placeholder("id")))
  .prepare("find_user_by_id");

// Usage in a route handler:
const [result] = await findUserById.execute({ id: "some-ulid" });

// ❌ BAD — creates a new prepared statement on every call
async function getUser(id: string) {
  const query = db
    .select()
    .from(user)
    .where(eq(user.id, sql.placeholder("id")))
    .prepare("get_user");
  return query.execute({ id });
}

Export inferred types for consumers:

export type FindUserById = Awaited<ReturnType<typeof findUserById.execute>>;