@farming-labs/orm

Drizzle

Drizzle integration in this repo is now both:

Basic config

import { defineConfig } from "@farming-labs/orm-cli";
import { authSchema } from "./src/schema";

export default defineConfig({
  schemas: [authSchema],
  targets: {
    drizzle: {
      out: "./generated/drizzle/schema.ts",
      dialect: "pg",
    },
  },
});

Supported Drizzle dialects

Runtime translation status

The repo now ships a live @farming-labs/orm-drizzle runtime package.

That means the unified query API can already run through Drizzle-backed apps for:

The current runtime package unwraps the underlying client from the Drizzle database handle and routes the unified API through the existing SQL runtime contract. From a library author point of view, that still means one stable API:

orm.user.findUnique(...)
orm.user.findMany(...)
orm.user.create(...)
orm.user.update(...)
orm.user.upsert(...)

That also means Drizzle inherits the SQL runtime's native relation-loading path. Reads such as session.user, session.user.profile, user.sessions, and simple explicit join-table manyToMany(...) branches can now load through one SQL statement. Relation branches still fall back when they add extra relation-level filtering, ordering, or paging.

That split is about the current Farming ORM planner, not a hard limit in Drizzle-backed SQL apps. As the SQL runtime grows richer native plans, Drizzle inherits them automatically.

That live Drizzle matrix now also verifies:

Runtime example

import { createOrm } from "@farming-labs/orm";
import { createDrizzleDriver } from "@farming-labs/orm-drizzle";
import { drizzle } from "drizzle-orm/node-postgres";
import { Pool } from "pg";
import { authSchema } from "./schema";

const pool = new Pool({
  connectionString: process.env.DATABASE_URL,
});

const db = drizzle(pool);

const orm = createOrm({
  schema: authSchema,
  driver: createDrizzleDriver({
    db,
    dialect: "postgres",
  }),
});

const user = await orm.user.findUnique({
  where: {
    email: "ada@farminglabs.dev",
  },
  select: {
    id: true,
    email: true,
    sessions: {
      select: {
        token: true,
      },
    },
  },
});

Example generated output

From:

user: model({
  table: "users",
  fields: {
    id: id(),
    email: string().unique().map("email_address"),
    createdAt: datetime().defaultNow(),
  },
});

the generator emits output shaped like:

export const user = pgTable("users", {
  id: text("id").primaryKey(),
  email: text("email_address").notNull().unique(),
  createdAt: timestamp("createdAt").notNull(),
});

If you want the generated Drizzle file as a string instead of writing it to disk, use renderDrizzleSchema(...) from @farming-labs/orm. The CLI page has the in-memory example: CLI generation.

For direct relations, the generator also emits relations(...) helpers for:

Join-table-backed manyToMany(...) is still represented through the explicit join model rather than a direct Drizzle relation shortcut.

How it fits into a Drizzle app

Typical flow:

  1. define the reusable schema once
  2. either run farm-orm generate drizzle for generated schema files
  3. or pass the live Drizzle database to createDrizzleDriver(...)
  4. keep writing one library-facing query API either way

That means Farming Labs ORM can either feed the app-side Drizzle stack through generation, or sit above it as a runtime translation layer.

Why Drizzle teams might like this

Important nuance

The Drizzle generator now covers the direct relation helpers above, and the live runtime already covers:

Generated Drizzle output still keeps many-to-many relationships explicit through the join model, which matches how Drizzle teams usually model those tables anyway.

Local verification

The repo verifies Drizzle locally against PostgreSQL, MySQL, and SQLite.

Run it with:

terminal
pnpm test:local:drizzle

Helpful references

· ·