@farming-labs/orm

Supabase

Supabase now fits through two honest paths:

Both paths keep the same schema definition and the same ORM query surface.

Which path to use

Use the PostgreSQL path when:

Use the direct Supabase JS path when:

PostgreSQL path

If you already have a pg pool or client connected to Supabase, use the PostgreSQL aliases in @farming-labs/orm-sql.

supabase-postgres-runtime.ts
import { createOrm } from "@farming-labs/orm";
import { createSupabasePoolDriver } from "@farming-labs/orm-sql";
import { Pool } from "pg";
import { appSchema } from "./schema";

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

const orm = createOrm({
  schema: appSchema,
  driver: createSupabasePoolDriver(pool),
});

If you already have a connected PostgreSQL client instead of a pool:

import { createOrm } from "@farming-labs/orm";
import { createSupabaseClientDriver } from "@farming-labs/orm-sql";

const orm = createOrm({
  schema: appSchema,
  driver: createSupabaseClientDriver(pgClient),
});

This path stays intentionally thin because it is still just PostgreSQL.

Direct Supabase JS path

If the app already has a Supabase client, use the dedicated runtime:

supabase-js-runtime.ts
import { createOrm } from "@farming-labs/orm";
import { createSupabaseDriver } from "@farming-labs/orm-supabase";
import { createClient } from "@supabase/supabase-js";
import { appSchema } from "./schema";

const supabase = createClient(process.env.SUPABASE_URL!, process.env.SUPABASE_SERVICE_ROLE_KEY!);

const orm = createOrm({
  schema: appSchema,
  driver: createSupabaseDriver({
    client: supabase,
  }),
});

Or let the runtime helpers detect it directly:

import { createOrmFromRuntime } from "@farming-labs/orm-runtime";

const orm = await createOrmFromRuntime({
  schema: appSchema,
  client: supabase,
});

This runtime uses Supabase's own client API. It does not wrap a hidden raw PostgreSQL bridge.

Setup helpers

If the package or framework needs to prepare the database before tests or setup flows, use the PostgreSQL path with the runtime-aware setup helpers:

import { pushSchema } from "@farming-labs/orm-runtime/setup";

await pushSchema({
  schema: appSchema,
  client: pool,
});

Or, if you want setup plus the ORM back:

import { bootstrapDatabase } from "@farming-labs/orm-runtime/setup";

const orm = await bootstrapDatabase({
  schema: appSchema,
  client: pool,
});

For the direct Supabase JS runtime, pushSchema(...) and applySchema(...) stay no-op. That path assumes the Supabase tables already exist.

Generated output

If the consuming app wants generated artifacts instead of only the live runtime, the same schema can still render:

import { renderDrizzleSchema, renderPrismaSchema, renderSafeSql } from "@farming-labs/orm";

const prismaSchema = renderPrismaSchema(appSchema, {
  provider: "postgresql",
});

const drizzleSchema = renderDrizzleSchema(appSchema, {
  dialect: "pg",
});

const sqlSchema = renderSafeSql(appSchema, {
  dialect: "postgres",
});

Connection guidance

Supabase's own docs are still the right place to choose the actual connection mode, TLS settings, and connection string for your environment:

Keep the provider-recommended TLS settings for your environment. Avoid disabling certificate verification in connection examples unless you are debugging a local-only setup and fully understand the tradeoff.

Why this matters

This lets a library or framework: