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

@remcostoeten/drizzleasy

v0.14.0

Published

Ultra-simple, type-safe CRUD operations for Next.js with Drizzle ORM

Readme

drizzleasy

Because who doesn't love abstractions on top of abstractions?

Drizzleasy is a library to make CRUD operations and database management ridiculously easy. 100% typesafe with full LSP support in your editor due to the chainable syntax.

Just see how easy creating, and rendering your data becomes

type Signup = { id: string; email: string; newsletter: 'yes' | 'no' }

async function createSignup(formData: FormData) {
  'use server' // mutations must be a server action
  await createFn<Signup>()('signups')({ //type with your expected data
    email: formData.get('email'),
    newsletter: formData.get('newsletter')
  })
  revalidatePath('/') // auto shows the posted result if queried
}

export default async function SignupApp() {
  const read = readFn<Signup>() // call the fnc defined with the object you expect
  const { data: premiumUsers } = await read('signups').where({ newsletter: 'newsletter' }) //await readFn, in the table
  return (
    <>
      <form action={createSignup}>
        <input name="email" placeholder="Email..." />
        <select name="newsletter">
          <option value="basic">Yes, sen me marketing mails</option>
          <option value="premium">No, do not mail me</option>
        </select>
        <button>Sign Up</button>
      </form>
      {premiumUsers?.map(user => <div key={user.id}>{user.email}</div>)}
    </>
  )
}
type TProps = { message: string }

async function createMsg(formData: FormData) {
  'use server' // must be server action
  await createFn<TProps>()('messages')({ // await create function and as string argument pass your drizzle schema
    message: formData.get('message'),
  })
  revalidatePath('/') // instantly show rendered results w/o refresh
}

export default async function MessageForm() {
  const { data: messages } = await readFn<TProps>()('messages')()
// await readFn function and assign your object which the data resembles and as  argument pass the schema name
  return (
    <>
      <form action={createMsg}>
        <textarea name="message" />
        <button>Send</button>
      </form>

  {messages?.map((msg, i) => (
        <div key={i}>{msg.message}</div>
      ))}
    </>
  )
}

npm version License: MIT

Features

  • One-liner setup - initializeConnection(url) replaces complex Drizzle setup
  • Auto-detection - Reads your drizzle.config.ts automatically
  • Multi-database - PostgreSQL (Neon, Vercel, Docker), SQLite, Turso
  • Simple syntax - Natural operators like age: '>18' and name: '*john*'
  • 100% type-safe - Full TypeScript support with IntelliSense
  • Optimistic updates - Built-in React hooks for smooth UX
  • Environment switching - Development/production database configs
  • Connection caching - Automatic connection reuse for performance
  • Dual module support - Works with both ESM and CommonJS
  • Zero dependencies - Only peer dependencies for database drivers

Installation

npm install @remcostoeten/drizzleasy

Quick Start

Replace 7 lines with 1 line

Before:

import { drizzle } from 'drizzle-orm/neon-http'
import { neon } from '@neondatabase/serverless'
import * as schema from './schema'

const sql = neon(process.env.DATABASE_URL!)
export const db = drizzle(sql, { schema, logger: true })

After:

import { initializeConnection } from '@remcostoeten/drizzleasy'
export const db = await initializeConnection(process.env.DATABASE_URL!)

Database Support

// PostgreSQL (Neon, Vercel, Supabase)
const db = await initializeConnection('postgresql://neon.tech/db')

// Local PostgreSQL (Docker)
const db = await initializeConnection('postgresql://localhost:5432/mydb')

// SQLite (Local file)
const db = await initializeConnection('file:./dev.db')

// Turso (with auth token)
const db = await initializeConnection('libsql://my-db.turso.io', {
    authToken: process.env.TURSO_AUTH_TOKEN
})

// Environment switching
const db = await initializeConnection({
    development: 'file:./dev.db',
    production: process.env.DATABASE_URL!
})

// Multiple databases
const dbs = await initializeConnection({
    main: process.env.DATABASE_URL!,
    analytics: process.env.ANALYTICS_URL!,
    cache: 'file:./cache.db'
})

CRUD Operations

import { readFn, createFn, updateFn, destroyFn } from '@remcostoeten/drizzleasy'

type User = {
    id: string
    name: string
    email: string
    age: number
    status: 'active' | 'inactive'
}

// Create factory functions
const read = readFn<User>()
const create = createFn<User>()
const update = updateFn<User>()
const destroy = destroyFn<User>()

// Read all records
const { data: users } = await read('users')()

// Read with natural WHERE syntax
const { data: activeUsers } = await read('users')
    .where({ status: 'active' })
    .where({ age: '>18' })
    .where({ name: '*john*' })()

// Create
const { data, error } = await create('users')({
    name: 'John',
    email: '[email protected]',
    age: 25,
    status: 'active'
})

// Update
await update('users')('user-123', { status: 'inactive' })

// Delete
await destroy('users')('user-123')

Database Connection

Auto-Detection

// PostgreSQL (Neon, Vercel, Docker)
const db = initializeConnection('postgresql://...')

// SQLite (Local file)
const db = initializeConnection('file:./dev.db')

// Turso (with auth token)
const db = initializeConnection('libsql://...', {
    authToken: process.env.TURSO_AUTH_TOKEN
})

Environment Switching

// Automatic environment detection
const db = initializeConnection({
    development: 'file:./dev.db',
    production: process.env.DATABASE_URL!
})

// Multiple databases
const dbs = initializeConnection({
    main: process.env.DATABASE_URL!,
    analytics: process.env.ANALYTICS_URL!,
    cache: 'file:./cache.db'
})

WHERE Syntax

// Comparison
{
    age: '>18'
} // Greater than
{
    price: '<=100'
} // Less than or equal
{
    status: '!inactive'
} // Not equal

// String patterns
{
    name: '*john*'
} // Contains
{
    name: 'john*'
} // Starts with
{
    email: '*@gmail.com'
} // Ends with

// Arrays (IN)
{
    role: ['admin', 'user']
}

// Direct equality
{
    status: 'active'
}

Module Support

Works with both ESM and CommonJS:

// ESM (recommended)
import {
    readFn,
    createFn,
    updateFn,
    destroyFn,
    initializeConnection
} from '@remcostoeten/drizzleasy'

// CommonJS
const {
    readFn,
    createFn,
    updateFn,
    destroyFn,
    initializeConnection
} = require('@remcostoeten/drizzleasy')

Error Handling

All operations return a consistent result format:

const create = createFn<User>()
const { data, error } = await create('users')({ name: 'John' })

if (error) {
    console.error('Operation failed:', error.message)
    return
}

console.log('Success:', data)

Contributing

Contributions are welcome! Please feel free to submit a Pull Request.

License

MIT © Remco Stoeten