The Convergence Point

The ORM We're All Trying to Build

Prisma pioneered elegant APIs but requires code generation and WASM. Drizzle went lightweight but sacrificed elegance. VibORM combines both: Prisma's elegant API, zero code generation, no WASM — pure TypeScript.

The Great ORM Convergence

In 2020, Prisma pioneered object-based queries and relational APIs. Drizzle launched as the "anti-Prisma" — lightweight, SQL-first, no abstractions. Now in 2025, Drizzle's v2 adopts the exact patterns they once dismissed.This isn't copying. It's convergence. Production demands these patterns.

Prisma's Path

  • Elegant, readable schemas
  • Intuitive query API
  • Code generation required
  • WASM engine overhead

Beautiful DX, but heavy toolchain

Drizzle's Path

  • Verbose, SQL-like schemas
  • Relations defined separately
  • Callback-based → object-based
  • Zero code generation

Lightweight, but sacrificed elegance

VibORM

  • Prisma's elegant API ✓
  • Zero code generation ✓
  • No WASM, pure TypeScript ✓
  • Database-agnostic features ✓

The best of both worlds

What Production Actually Demands

These patterns aren't arbitrary preferences — they're optimal solutions that emerge when you tackle production-scale problems.

Complete object-based queries

Drizzle v2 adopted object-based patterns but only partially — missing nested selects on relations and other features. VibORM implements the full Prisma-like API.

"where is now object. orderBy is now object."Drizzle v2 Migration Docs

Schema elegance isn't optional

Drizzle forces you to define relations separately from models. That's not just inconvenient — it's harder to understand and maintain. VibORM keeps relations inline, like Prisma.

"Your schema should be readable at a glance, not scattered across files."Developer Experience

Typed JSON columns

Other ORMs treat JSON as 'any'. VibORM lets you define JSON schemas with Zod or Valibot — full type inference and runtime validation on your JSON data.

"JSON columns shouldn't be a type safety escape hatch."Type Safety

No WASM, no complexity

Prisma bundles a Rust engine compiled to WASM — extra binaries, platform issues, slower cold starts. VibORM is pure TypeScript. Nothing to download, nothing to compile.

"The simplest architecture is the best architecture."Engineering Wisdom

Elegance Matters

Drizzle requires relations to be defined separately from your models. VibORM keeps everything together — like Prisma, but in pure TypeScript.

drizzle-schema.tsDrizzle
// Tables defined here...
const users = pgTable("users", {
  id: text("id").primaryKey(),
  email: text("email").notNull().unique(),
  name: text("name"),
});

const posts = pgTable("posts", {
  id: text("id").primaryKey(),
  title: text("title").notNull(),
  authorId: text("author_id").references(() => users.id),
});

// ...but relations defined separately 😕
const usersRelations = relations(users, ({ many }) => ({
  posts: many(posts),
}));

const postsRelations = relations(posts, ({ one }) => ({
  author: one(users, {
    fields: [posts.authorId],
    references: [users.id],
  }),
}));
viborm-schema.tsVibORM
// Everything in one place — clean & elegant ✨
const user = s.model({
  id: s.string().id().ulid(),
  email: s.string().unique(),
  name: s.string().nullable(),
  posts: s.relation.oneToMany(() => post),
}).map("users");

const post = s.model({
  id: s.string().id().ulid(),
  title: s.string(),
  authorId: s.string(),
  author: s.relation
    .fields("authorId")
    .references("id")
    .manyToOne(() => user),
}).map("posts");

// That's it. Relations are part of the model.
// Chainable. Readable. Elegant.

Drizzle's Approach

  • • Relations defined in separate relations() calls
  • • Schema scattered across multiple declarations
  • • Harder to understand model structure at a glance
  • • More boilerplate, less readable

VibORM's Approach

  • • Relations defined inline with the model
  • • One model = one complete definition
  • • Immediately see the full picture
  • • Chainable, fluent, Prisma-like elegance

Your Schema Library, Native Support

Use Zod, Valibot, or ArkType to narrow field validation. Define typed JSON columns with full inference. No other ORM does this.

typed-json.tsTyped JSON
import { s } from "viborm";
import { z } from "zod";

// Define your JSON structure with Zod
const addressSchema = z.object({
  street: z.string(),
  city: z.string(),
  zip: z.string(),
  country: z.string(),
});

const user = s.model({
  id: s.string().id().ulid(),
  email: s.string().unique(),
  // Typed JSON column with full inference ✨
  address: s.json(addressSchema),
  // Nullable typed JSON
  preferences: s.json(prefsSchema).nullable(),
}).map("users");

// TypeScript knows address is { street, city, zip, country }
// Runtime validation included — invalid JSON throws
narrowed-validation.tsStandard Schema
import { s } from "viborm";
import { z } from "zod";
import * as v from "valibot";

// Use Zod for email validation
const user = s.model({
  id: s.string().id().ulid(),
  email: s.string().validator(
    z.string().email()
  ),
  // Or use Valibot
  phone: s.string().validator(
    v.pipe(v.string(), v.regex(/^\+[0-9]{10,15}$/))
  ),
  // Or ArkType
  age: s.int().validator(type("number > 0 & < 150")),
}).map("users");

// Works with any Standard Schema compliant library
// Same API, your choice of validator
Zod

Most popular schema library

Valibot

Lightweight alternative

ArkType

Fastest runtime validation

JSON Columns, Finally Type-Safe

Other ORMs treat JSON as any or unknown. VibORM lets you define the exact shape with your favorite schema library — full type inference in queries, runtime validation on writes. No more JSON escape hatches.

Queries That Read Like English

Prisma's query API is beloved for a reason — it's intuitive. VibORM brings that same elegance without the code generation.

queries.tsPrisma-like API
// Find admins with their published posts
const admins = await client.user.findMany({
  where: { role: "ADMIN" },
  include: {
    posts: {
      where: { published: true },
      orderBy: { createdAt: "desc" },
    },
  },
});

// Create a user with posts in one call
const newUser = await client.user.create({
  data: {
    email: "alice@example.com",
    name: "Alice",
    posts: {
      create: [
        { title: "Hello World" },
        { title: "Second Post" },
      ],
    },
  },
  include: { posts: true },
});

// TypeScript knows the exact return type
// No generation. No guessing. Just inference.

Simpler Stack, Better Performance

No prisma generate. No WASM engine. No binary downloads. Just pure TypeScript that runs anywhere Node.js runs — faster cold starts, simpler deployments, and the complete Prisma-like query API.

The Full Picture

Prisma's elegance. Drizzle's zero-generation. VibORM combines both — without the compromises.

FeaturePrismaDrizzle v1Drizzle v2VibORM
Object-based queriesPartialComplete
Zero code generation
Pure TypeScript (no WASM)
Full type inferenceGeneratedPartialPartialFull
Relational queriesLimited
Typed JSON columns
Standard Schema integrationZod/Valibot/ArkType
Exported model schemasArkType
TypeScript schemaPSL file
Relations inline
Filtering by relations
Nested select on relationsPartial
Scalar arrays on MySQL
DISTINCT on all databasesPartialDB-dependentDB-dependent
Consistent feature setDB-dependentDB-dependentDB-dependentAlways

Prisma has elegance but requires generation and WASM. Drizzle is lightweight but sacrificed elegance. VibORM gives you both — beautiful queries, pure TypeScript, no build step.

One API. Every Database. Every Feature.

Other ORMs give you different features depending on your database. VibORM abstracts the limitations away — your code works the same whether you're on PostgreSQL, MySQL, or SQLite.

Scalar Arrays

MySQL doesn't support array columns natively. VibORM emulates them with JSON — same API, same types, any database.

DISTINCT Queries

DISTINCT ON isn't available everywhere. VibORM provides consistent distinct behavior across all supported databases.

Switch Anytime

Start with SQLite for development, deploy to PostgreSQL. Your queries don't change — the ORM handles the translation.

The Real Abstraction

Most ORMs abstract SQL syntax — you still hit database limitations. VibORM abstracts database capabilities. Features that don't exist natively are emulated transparently. You get the same powerful API everywhere.

Features That Survived Convergence

These aren't arbitrary preferences. They're the patterns that every production ORM eventually implements.

Prisma's Elegance

Chainable schemas. Relations defined inline. Queries that read like English. The beautiful DX Prisma pioneered — in pure TypeScript.

Relations Done Right

Defined inline, not scattered. include, nested select, relation filters — Prisma's complete relational API without the separate relations() boilerplate.

Full Type Safety

Every query, filter, and result is typed. No any, no guessing, no runtime surprises.

Pure TypeScript

No code generation, no WASM engine, no binary downloads. Just TypeScript — simpler workflow, faster cold starts, works everywhere.

Exported Model Schemas

ArkType schemas auto-generated from your models. Use them for API validation, form validation — anywhere you need runtime checks outside the ORM.

Standard Schema Integration

Use Zod, Valibot, or ArkType to narrow field validation and type JSON columns. Your favorite schema library, native support.

True Database Abstraction

Scalar arrays on MySQL. DISTINCT on SQLite. Every feature works everywhere — the ORM abstracts database limitations, not just syntax.

Skip the Convergence. Start at the Destination.

Why wait for other ORMs to implement what you need? VibORM has the patterns that production demands — today.

$npm install viborm