One schema. Many stacks.
@farming-labs/orm lets you write your schema and storage layer once, then
translate it across Prisma, Drizzle, Kysely, MikroORM, TypeORM, Sequelize,
EdgeDB / Gel, Neo4j, SurrealDB, Cloudflare D1, Cloudflare KV, Redis / Upstash Redis,
Supabase JS, Xata, direct SQL, Firestore, DynamoDB, Unstorage, MongoDB, and
Mongoose.
It gives you:
- one schema definition in TypeScript
- one typed query API
- generated Prisma, Drizzle, and safe SQL artifacts
- runtime helpers that accept raw clients and build the ORM for you
@farming-labs/ormCore schema DSL, typed client, generators, and memory driver@farming-labs/orm-cliCLI for generating Prisma, Drizzle, and SQL artifacts@farming-labs/orm-runtimeHelpers for detecting a raw client and creating a driver or ORM from it@farming-labs/orm-prismaPrisma runtime driver@farming-labs/orm-drizzleDrizzle runtime driver@farming-labs/orm-kyselyKysely runtime driver@farming-labs/orm-mikroormMikroORM runtime driver@farming-labs/orm-typeormTypeORM runtime driver@farming-labs/orm-sequelizeSequelize runtime driver@farming-labs/orm-edgedbEdgeDB / Gel SQL runtime driver@farming-labs/orm-neo4jNeo4j graph runtime driver@farming-labs/orm-surrealdbSurrealDB multi-model runtime driver@farming-labs/orm-d1Cloudflare D1 runtime driver@farming-labs/orm-kvCloudflare KV runtime driver@farming-labs/orm-redisRedis and Upstash-compatible runtime driver@farming-labs/orm-supabaseSupabase JS runtime driver@farming-labs/orm-xataXata runtime driver@farming-labs/orm-sqlDirect SQL runtime driver@farming-labs/orm-firestoreServer-side Firestore runtime driver@farming-labs/orm-dynamodbDynamoDB runtime driver@farming-labs/orm-unstorageUnstorage runtime driver for lightweight key-value/document storage@farming-labs/orm-mongoNative MongoDB runtime driver@farming-labs/orm-mongooseMongoose runtime driver
import { belongsTo, createOrm, defineSchema, hasMany, id, model, string } from "@farming-labs/orm";
import { createPgPoolDriver } from "@farming-labs/orm-sql";
import { Pool } from "pg";
const schema = defineSchema({
user: model({
table: "users",
fields: {
id: id(),
email: string().unique(),
name: string(),
},
relations: {
sessions: hasMany("session", { foreignKey: "userId" }),
},
}),
session: model({
table: "sessions",
fields: {
id: id(),
userId: string().references("user.id"),
token: string().unique(),
},
relations: {
user: belongsTo("user", { foreignKey: "userId" }),
},
}),
});
const orm = createOrm({
schema,
driver: createPgPoolDriver(
new Pool({
connectionString: process.env.DATABASE_URL,
}),
),
});
const user = await orm.user.findOne({
where: { email: "ada@farminglabs.dev" },
select: {
id: true,
email: true,
sessions: {
select: {
token: true,
},
},
},
});If you already have a raw runtime client, let the helper package detect it and build the ORM:
import { createOrmFromRuntime } from "@farming-labs/orm-runtime";
import { Pool } from "pg";
const orm = await createOrmFromRuntime({
schema,
client: new Pool({
connectionString: process.env.DATABASE_URL,
}),
});
orm.$driver.kind; // "sql"
orm.$driver.capabilities.supportsTransactions; // trueYou can also inspect a client before building anything:
import { inspectDatabaseRuntime } from "@farming-labs/orm";
const report = inspectDatabaseRuntime(client);
report.runtime;
report.summary;Cloudflare Worker bindings work through the same helper path too:
const orm = await createOrmFromRuntime({
schema,
client: env.DB,
});
orm.$driver.kind; // "d1"import { defineConfig } from "@farming-labs/orm-cli";
import { schema } from "./src/schema";
export default defineConfig({
schemas: [schema],
targets: {
prisma: {
out: "./generated/prisma/schema.prisma",
provider: "postgresql",
},
drizzle: {
out: "./generated/drizzle/schema.ts",
dialect: "pg",
},
sql: {
out: "./generated/sql/0001_init.sql",
dialect: "postgres",
},
},
});farm-orm generate prisma
farm-orm generate drizzle
farm-orm generate sqlThe full guides live in the docs app under apps/docs.