Update Drizzle ORM Adapter to support the new Drizzle ORM query syntax (drizzle-orm v1.0.0) #2532

Open
opened 2026-03-13 10:01:07 -05:00 by GiteaMirror · 12 comments
Owner

Originally created by @ghassenbenghorbal on GitHub (Dec 15, 2025).

Originally assigned to: @ping-maxwell on GitHub.

Is this suited for github?

  • Yes, this is suited for github

I migrated to the new drizzle-orm@beta but now I can't use better-auth because the drizzle orm adapter does not support the new syntax

10 |            function getSchema(model) {
11 |                    const schema = config.schema || db$1._.fullSchema;
12 |                    if (!schema) throw new BetterAuthError("Drizzle adapter failed to initialize. Schema not found. Please provide a schema object in the adapter options object.");
13 |                    const schemaModel = schema[model];
14 |                    if (!schemaModel) throw new BetterAuthError(`[# Drizzle Adapter]: The model "${model}" was not found in the schema object. Please pass the schema directly to the adapter options.`);
                                    ^
BetterAuthError: [# Drizzle Adapter]: The model "user" was not found in the schema object. Please pass the schema directly to the adapter options.
 cause: undefined,

Describe the solution you'd like

Update Drizzle ORM Adapter to support drizzle-orm@beta (v1.0)

Describe alternatives you've considered

None

Additional context

No response

Originally created by @ghassenbenghorbal on GitHub (Dec 15, 2025). Originally assigned to: @ping-maxwell on GitHub. ### Is this suited for github? - [x] Yes, this is suited for github ### Is your feature request related to a problem? Please describe. I migrated to the new drizzle-orm@beta but now I can't use better-auth because the drizzle orm adapter does not support the new syntax ```javascript9 | const createCustomAdapter = (db$1) => ({ getFieldName, options }) => { 10 | function getSchema(model) { 11 | const schema = config.schema || db$1._.fullSchema; 12 | if (!schema) throw new BetterAuthError("Drizzle adapter failed to initialize. Schema not found. Please provide a schema object in the adapter options object."); 13 | const schemaModel = schema[model]; 14 | if (!schemaModel) throw new BetterAuthError(`[# Drizzle Adapter]: The model "${model}" was not found in the schema object. Please pass the schema directly to the adapter options.`); ^ BetterAuthError: [# Drizzle Adapter]: The model "user" was not found in the schema object. Please pass the schema directly to the adapter options. cause: undefined, ``` ### Describe the solution you'd like Update Drizzle ORM Adapter to support drizzle-orm@beta (v1.0) ### Describe alternatives you've considered None ### Additional context _No response_
GiteaMirror added the adapter label 2026-03-13 10:01:07 -05:00
Author
Owner

@dosubot[bot] commented on GitHub (Dec 15, 2025):

The Drizzle ORM adapter in better-auth does not yet fully support the new query syntax and schema handling introduced in drizzle-orm v1.0.0. The adapter currently relies on APIs like db._.fullSchema and db.query, which have changed or been removed in v1.0.0, leading to errors like "model 'user' was not found in the schema object" and breaking compatibility with the new Drizzle ORM release adapter code.

Recent documentation updates show that you must manually merge Better Auth's generated schema with your app schema and map table names (for example, mapping user to users if your schema uses plural names) when creating your Drizzle instance and passing the schema to the adapter docs PR. For experimental joins and relations, you need to include relations defined with Drizzle's relations() helper and ensure the schema object passed to Drizzle and the adapter contains all required tables and relations issue.

To work around current limitations, merge your schemas and map table/field names as needed. Remove the usePlural option if your schema keys are already pluralized. However, full support for Drizzle ORM v1.0.0's new query syntax will require updates to the adapter's internals, including schema/model resolution, query construction, and relation handling adapter code.

For now, you can follow the updated documentation for schema merging and mapping, but expect that some features (especially advanced queries and joins) may not work until the adapter is officially updated for v1.0.0 compatibility docs PR.

To reply, just mention @dosu.


How did I do? Good | Irrelevant | Incorrect | Verbose | Hallucination | Report 🐛 | Other

Chat with Dosu Open in Cursor Join Discord Share on X

@dosubot[bot] commented on GitHub (Dec 15, 2025): <!-- Answer --> The Drizzle ORM adapter in better-auth does not yet fully support the new query syntax and schema handling introduced in drizzle-orm v1.0.0. The adapter currently relies on APIs like `db._.fullSchema` and `db.query`, which have changed or been removed in v1.0.0, leading to errors like "model 'user' was not found in the schema object" and breaking compatibility with the new Drizzle ORM release [adapter code](https://github.com/better-auth/better-auth/blob/f59fe3a19974805357d3f6dd54731247c0be3f3c/packages/better-auth/src/adapters/drizzle-adapter/drizzle-adapter.ts#L78-L597). Recent documentation updates show that you must manually merge Better Auth's generated schema with your app schema and map table names (for example, mapping `user` to `users` if your schema uses plural names) when creating your Drizzle instance and passing the schema to the adapter [docs PR](https://github.com/better-auth/better-auth/pull/6117). For experimental joins and relations, you need to include relations defined with Drizzle's `relations()` helper and ensure the schema object passed to Drizzle and the adapter contains all required tables and relations [issue](https://github.com/better-auth/better-auth/issues/6200#issuecomment-3566777289). To work around current limitations, merge your schemas and map table/field names as needed. Remove the `usePlural` option if your schema keys are already pluralized. However, full support for Drizzle ORM v1.0.0's new query syntax will require updates to the adapter's internals, including schema/model resolution, query construction, and relation handling [adapter code](https://github.com/better-auth/better-auth/blob/f59fe3a19974805357d3f6dd54731247c0be3f3c/packages/better-auth/src/adapters/drizzle-adapter/drizzle-adapter.ts#L78-L597). For now, you can follow the updated documentation for schema merging and mapping, but expect that some features (especially advanced queries and joins) may not work until the adapter is officially updated for v1.0.0 compatibility [docs PR](https://github.com/better-auth/better-auth/pull/6117). <!-- Dosu Comment Footer --> *To reply, just mention [@dosu](https://go.dosu.dev/dosubot).* --- <sup>How did I do? [Good](https://app.dosu.dev/response-feedback/a8583b1e-5feb-4a67-b1ff-d1e614393fa8?feedback_type=great_response) | [Irrelevant](https://app.dosu.dev/response-feedback/a8583b1e-5feb-4a67-b1ff-d1e614393fa8?feedback_type=irrelevant_answer) | [Incorrect](https://app.dosu.dev/response-feedback/a8583b1e-5feb-4a67-b1ff-d1e614393fa8?feedback_type=incorrect_sources) | [Verbose](https://app.dosu.dev/response-feedback/a8583b1e-5feb-4a67-b1ff-d1e614393fa8?feedback_type=too_verbose) | [Hallucination](https://app.dosu.dev/response-feedback/a8583b1e-5feb-4a67-b1ff-d1e614393fa8?feedback_type=hallucination) | [Report 🐛](https://app.dosu.dev/response-feedback/a8583b1e-5feb-4a67-b1ff-d1e614393fa8?feedback_type=bug_report) | [Other](https://app.dosu.dev/response-feedback/a8583b1e-5feb-4a67-b1ff-d1e614393fa8?feedback_type=other)</sup> [![Chat with Dosu](https://dosu.dev/dosu-chat-badge.svg)](https://app.dosu.dev/cdda13d9-dd27-4d31-b09a-5d8bec92de21/ask?utm_source=github)&nbsp;[![Open in Cursor](https://dosu.dev/dosu-in-cursor.svg)](https://cursor.com/link/prompt?text=The%20Drizzle%20ORM%20adapter%20in%20better-auth%20does%20not%20yet%20fully%20support%20the%20new%20query%20syntax%20and%20schema%20handling%20introduced%20in%20drizzle-orm%20v1.0.0.%20The%20adapter%20currently%20relies%20on%20APIs%20like%20%60db._.fullSchema%60%20and%20%60db.query%60%2C%20which%20have%20changed%20or%20been%20removed%20in%20v1.0.0%2C%20leading%20to%20errors%20like%20%22model%20%27user%27%20was%20not%20found%20in%20the%20schema%20object%22%20and%20breaking%20compatibility%20with%20the%20new%20Drizzle%20ORM%20release%C2%A0%5Badapter%20code%5D%28https%3A//github.com/better-auth/better-auth/blob/f59fe3a19974805357d3f6dd54731247c0be3f3c/packages/better-auth/src/adapters/drizzle-adapter/drizzle-adapter.ts%23L78-L597%29.%0A%0ARecent%20documentation%20updates%20show%20that%20you%20must%20manually%20merge%20Better%20Auth%27s%20generated%20schema%20with%20your%20app%20schema%20and%20map%20table%20names%20%28for%20example%2C%20mapping%20%60user%60%20to%20%60users%60%20if%20your%20schema%20uses%20plural%20names%29%20when%20creating%20your%20Drizzle%20instance%20and%20passing%20the%20schema%20to%20the%20adapter%C2%A0%5Bdocs%20PR%5D%28https%3A//github.com/better-auth/better-auth/pull/6117%29.%20For%20experimental%20joins%20and%20relations%2C%20you%20need%20to%20include%20relations%20defined%20with%20Drizzle%27s%20%60relations%28%29%60%20helper%20and%20ensure%20the%20schema%20object%20passed%20to%20Drizzle%20and%20the%20adapter%20contains%20all%20required%20tables%20and%20relations%C2%A0%5Bissue%5D%28https%3A//github.com/better-auth/better-auth/issues/6200%23issuecomment-3566777289%29.%0A%0ATo%20work%20around%20current%20limitations%2C%20merge%20your%20schemas%20and%20map%20table/field%20names%20as%20needed.%20Remove%20the%20%60usePlural%60%20option%20if%20your%20schema%20keys%20are%20already%20pluralized.%20However%2C%20full%20support%20for%20Drizzle%20ORM%20v1.0.0%27s%20new%20query%20syntax%20will%20require%20updates%20to%20the%20adapter%27s%20internals%2C%20including%20schema/model%20resolution%2C%20query%20construction%2C%20and%20relation%20handling%C2%A0%5Badapter%20code%5D%28https%3A//github.com/better-auth/better-auth/blob/f59fe3a19974805357d3f6dd54731247c0be3f3c/packages/better-auth/src/adapters/drizzle-adapter/drizzle-adapter.ts%23L78-L597%29.%0A%0AFor%20now%2C%20you%20can%20follow%20the%20updated%20documentation%20for%20schema%20merging%20and%20mapping%2C%20but%20expect%20that%20some%20features%20%28especially%20advanced%20queries%20and%20joins%29%20may%20not%20work%20until%20the%20adapter%20is%20officially%20updated%20for%20v1.0.0%20compatibility%C2%A0%5Bdocs%20PR%5D%28https%3A//github.com/better-auth/better-auth/pull/6117%29.)&nbsp;[![Join Discord](https://img.shields.io/badge/join-5865F2?logo=discord&logoColor=white&label=)](https://go.dosu.dev/discord-bot)&nbsp;[![Share on X](https://img.shields.io/badge/X-share-black)](https://twitter.com/intent/tweet?text=%40dosu_ai%20helped%20me%20solve%20this%20issue!&url=https%3A//github.com/better-auth/better-auth/issues/6766)
Author
Owner

@CBell045 commented on GitHub (Dec 17, 2025):

I was having this issue as well. Passing my schema and relations to my drizzle adapter seems to have fixed it:

import "dotenv/config";
import * as schema from "./schema";
import { relations } from "./relations";
import { drizzle } from "drizzle-orm/bun-sql";

export const db = drizzle({
  connection: process.env.DATABASE_URL!,
  casing: "snake_case",
  schema,
  relations,
});
@CBell045 commented on GitHub (Dec 17, 2025): I was having this issue as well. Passing my schema and relations to my drizzle adapter seems to have fixed it: ``` import "dotenv/config"; import * as schema from "./schema"; import { relations } from "./relations"; import { drizzle } from "drizzle-orm/bun-sql"; export const db = drizzle({ connection: process.env.DATABASE_URL!, casing: "snake_case", schema, relations, }); ```
Author
Owner

@matulef commented on GitHub (Dec 21, 2025):

Even if you pass the schema, I think there is still a compatibility issue with the new drizzle 1.0 syntax. It occurs if you have joins turned on. The error I get is Unknown relational filter field: "decoder". If I comment out experimental joins in my auth config, e.g.

// experimental: { joins: true }

then it works because it doesn't rely on the drizzle-defined relations. But ideally, we'd be able to use the new drizzle and get the benefit of joins in better-auth too.

I think this can be done in a backwards compatible way by replacing db.query with db._query if it's defined. See here: https://orm.drizzle.team/docs/relations-v1-v2

@matulef commented on GitHub (Dec 21, 2025): Even if you pass the schema, I think there is still a compatibility issue with the new drizzle 1.0 syntax. It occurs if you have joins turned on. The error I get is `Unknown relational filter field: "decoder"`. If I comment out experimental joins in my auth config, e.g. ``` // experimental: { joins: true } ``` then it works because it doesn't rely on the drizzle-defined relations. But ideally, we'd be able to use the new drizzle and get the benefit of joins in better-auth too. I think this can be done in a backwards compatible way by replacing db.query with db._query if it's defined. See here: https://orm.drizzle.team/docs/relations-v1-v2
Author
Owner

@ping-maxwell commented on GitHub (Jan 2, 2026):

Hello all, I've already opened a PR on this. Just minor details relating to CI to get working and it will be merged.
https://github.com/better-auth/better-auth/pull/6913

Usage

You can use it today by installing the following:

npm i https://pkg.pr.new/better-auth/better-auth/@better-auth/drizzle-adapter@6913

After installing, update your imports: (note the new drizzle-adapter import path)

import { betterAuth } from "better-auth";
import { drizzleAdapter } from "@better-auth/drizzle-adapter/relations-v2"; 
import { db } from "./database.ts";
import * as schema from "./schema.ts";

export const auth = betterAuth({
  database: drizzleAdapter(db, {
    provider: "sqlite", // or "pg" or "mysql"
    schema,
  }),
  //... the rest of your config
});

Then regenerate your schema using the Better Auth CLI:

pnpx https://pkg.pr.new/better-auth/better-auth/@better-auth/cli@6913 generate
You do not need to run database migrations when upgrading to Relations v2. The database structure remains the same - only the relation definitions change. The schema generator will output the new v2 format automatically.

And apply the new relations to your drizzle instance:

import { drizzle } from "drizzle-orm/...";
import * as schemas from "./schema.ts";

const { relations, ...schema } = schemas;

export const db = drizzle({
  client,
  schema, 
  relations, 
});

Post-release

Once the PR is merged, you may install the released package:

npm i @better-auth/drizzle-adapter

In the future, it will be expected to use our drizzle-adapter package, and the better-auth exported drizzle adapter will be deprecated.

@ping-maxwell commented on GitHub (Jan 2, 2026): Hello all, I've already opened a PR on this. Just minor details relating to CI to get working and it will be merged. https://github.com/better-auth/better-auth/pull/6913 ## Usage You can use it today by installing the following: ```bash npm i https://pkg.pr.new/better-auth/better-auth/@better-auth/drizzle-adapter@6913 ``` After installing, update your imports: (note the new drizzle-adapter import path) ```ts title="auth.ts" import { betterAuth } from "better-auth"; import { drizzleAdapter } from "@better-auth/drizzle-adapter/relations-v2"; import { db } from "./database.ts"; import * as schema from "./schema.ts"; export const auth = betterAuth({ database: drizzleAdapter(db, { provider: "sqlite", // or "pg" or "mysql" schema, }), //... the rest of your config }); ``` Then regenerate your schema using the Better Auth CLI: ```package-install pnpx https://pkg.pr.new/better-auth/better-auth/@better-auth/cli@6913 generate ``` <Callout type="info"> You do not need to run database migrations when upgrading to Relations v2. The database structure remains the same - only the relation definitions change. The schema generator will output the new v2 format automatically. </Callout> And apply the new relations to your drizzle instance: ```ts import { drizzle } from "drizzle-orm/..."; import * as schemas from "./schema.ts"; const { relations, ...schema } = schemas; export const db = drizzle({ client, schema, relations, }); ``` ## Post-release Once the PR is merged, you may install the released package: ```bash npm i @better-auth/drizzle-adapter ``` In the future, it will be expected to use our drizzle-adapter package, and the better-auth exported drizzle adapter will be deprecated.
Author
Owner

@RihanArfan commented on GitHub (Jan 5, 2026):

For anyone using this before it's merged, make sure to also use the PR's CLI version too:

- npx @better-auth/cli@latest generate
+ pnpx https://pkg.pr.new/better-auth/better-auth/@better-auth/cli@6913 generate
@RihanArfan commented on GitHub (Jan 5, 2026): For anyone using this before it's merged, make sure to also use the PR's CLI version too: ```diff - npx @better-auth/cli@latest generate + pnpx https://pkg.pr.new/better-auth/better-auth/@better-auth/cli@6913 generate ```
Author
Owner

@ping-maxwell commented on GitHub (Jan 5, 2026):

Good callout 🫡

@ping-maxwell commented on GitHub (Jan 5, 2026): Good callout 🫡
Author
Owner

@dotnize commented on GitHub (Jan 19, 2026):

Something to consider: can we maybe have the CLI's autogenerated schema use defineRelationsPart instead of defineRelations?

https://orm.drizzle.team/docs/relations-v2#relations-parts

Drizzle only accepts 1 main relations object defined by defineRelations, and ideally this should probably be our own defined relations from our own schema.

Currently the CLI generates the "main" relations, so for our own custom relations outside auth, we have to use defineRelationsPart.

This works and it's not really a big deal but I'm just wondering if it's a good idea to make it the other way around :) Thank you!

@dotnize commented on GitHub (Jan 19, 2026): Something to consider: can we maybe have the CLI's autogenerated schema use `defineRelationsPart` instead of `defineRelations`? https://orm.drizzle.team/docs/relations-v2#relations-parts Drizzle only accepts 1 main `relations` object defined by defineRelations, and ideally this should probably be our own defined relations from our own schema. Currently the CLI generates the "main" relations, so for our own custom relations outside auth, we have to use `defineRelationsPart`. This works and it's not really a big deal but I'm just wondering if it's a good idea to make it the other way around :) Thank you!
Author
Owner

@ping-maxwell commented on GitHub (Jan 19, 2026):

@dotnize will do

@ping-maxwell commented on GitHub (Jan 19, 2026): @dotnize will do
Author
Owner

@EDM115 commented on GitHub (Jan 31, 2026):

for anyone interested, I wrote a "codemod-like" script to make the better-auth cli generated schema to be compatible with drizzle v2 relational queries, although this is a band-aid :

/* oxlint-disable @typescript-eslint/no-explicit-any */

import fs from "node:fs"
import path from "node:path"
import ts from "typescript"

/**
 * Example usage : tsx shared/db/fix-auth-relations.codemod.ts shared/db/auth.schema.ts --write  
 * Without --write, prints the transformed file to stdout
 */

const argv = process.argv.slice(2)
const filePathArg = argv.find((a) => !a.startsWith("--")) ?? "shared/db/auth.schema.ts"
const shouldWrite = argv.includes("--write")

const filePath = path.resolve(process.cwd(), filePathArg)
const input = fs.readFileSync(filePath, "utf8")

const sf = ts.createSourceFile(filePath, input, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS)

// ---------- helpers ----------

const f = ts.factory

function isCall(node: ts.Node, name: string): node is ts.CallExpression {
  return ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === name
}

function isSqliteTableDecl(stmt: ts.Statement): stmt is ts.VariableStatement {
  if (!ts.isVariableStatement(stmt)) {
    return false
  }

  if (!stmt.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)) {
    return false
  }

  const decl = stmt.declarationList.declarations[0]

  if (!decl || !ts.isIdentifier(decl.name) || !decl.initializer) {
    return false
  }

  return ts.isCallExpression(decl.initializer) && ts.isIdentifier(decl.initializer.expression)
    ? decl.initializer.expression.text === "sqliteTable"
    : false
}

function isRelationsConstDecl(stmt: ts.Statement): stmt is ts.VariableStatement {
  if (!ts.isVariableStatement(stmt)) {
    return false
  }

  if (!stmt.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)) {
    return false
  }

  const decl = stmt.declarationList.declarations[0]

  if (!decl || !ts.isIdentifier(decl.name) || !decl.initializer) {
    return false
  }

  return isCall(decl.initializer, "relations")
}

function unwrapSingleArray(expr: ts.Expression): ts.Expression {
  if (ts.isArrayLiteralExpression(expr) && expr.elements.length === 1) {
    const el = expr.elements[0]

    if (!el) {
      return expr
    }

    return ts.isSpreadElement(el)
      ? expr
      : el
  }

  return expr
}

function toRColumn(expr: ts.Expression): ts.Expression {
  // Convert : table.column  ->  r.table.column
  // Keep everything else as-is
  if (ts.isPropertyAccessExpression(expr) && ts.isIdentifier(expr.expression)) {
    const tableName = expr.expression.text
    const colName = expr.name.text

    return f.createPropertyAccessExpression(
      f.createPropertyAccessExpression(f.createIdentifier("r"), f.createIdentifier(tableName)),
      f.createIdentifier(colName),
    )
  }

  // Also handle nested forms like : someAlias.userId?
  // We only rewrite identifier.property
  return expr
}

function mapConfigObject(obj: ts.ObjectLiteralExpression): {
  from?: ts.Expression; to?: ts.Expression; alias?: ts.Expression; otherProps: ts.ObjectLiteralElementLike[];
} {
  let from: ts.Expression | undefined
  let to: ts.Expression | undefined
  let alias: ts.Expression | undefined

  const otherProps: ts.ObjectLiteralElementLike[] = []

  for (const prop of obj.properties) {
    if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name)) {
      otherProps.push(prop)

      continue
    }

    const key = prop.name.text
    const value = prop.initializer

    if (key === "fields") {
      // fields : [session.userId] -> from: r.session.userId
      const v = unwrapSingleArray(value)

      from = ts.isArrayLiteralExpression(v)
        ? f.createArrayLiteralExpression(v.elements.map((e) => toRColumn(e)))
        : toRColumn(v)

      continue
    }

    if (key === "references") {
      // references : [user.id] -> to: r.user.id
      const v = unwrapSingleArray(value)

      to = ts.isArrayLiteralExpression(v)
        ? f.createArrayLiteralExpression(v.elements.map((e) => toRColumn(e)))
        : toRColumn(v)

      continue
    }

    if (key === "relationName") {
      // relationName -> alias
      alias = value

      continue
    }

    // keep any unknown config options (future-proof)
    otherProps.push(prop)
  }

  return {
    from, to, alias, otherProps,
  }
}

type V1RelationProp
  = | {
    kind: "many";
    propName: string;
    targetTable: string;
    aliasExpr?: ts.Expression;
    extraConfigProps?: ts.ObjectLiteralElementLike[];
  }
  | {
    kind: "one";
    propName: string;
    targetTable: string;
    from?: ts.Expression;
    to?: ts.Expression;
    aliasExpr?: ts.Expression;
    extraConfigProps?: ts.ObjectLiteralElementLike[];
  }

function parseV1RelationsObject(obj: ts.ObjectLiteralExpression): V1RelationProp[] {
  const out: V1RelationProp[] = []

  for (const p of obj.properties) {
    if (!ts.isPropertyAssignment(p)) {
      continue
    }

    const propName = ts.isIdentifier(p.name)
      ? p.name.text
      : ts.isStringLiteral(p.name)
        ? p.name.text
        : undefined

    if (!propName) {
      continue
    }

    const init = p.initializer

    if (!ts.isCallExpression(init) || !ts.isIdentifier(init.expression)) {
      continue
    }

    // "many" | "one"
    const callee = init.expression.text
    const firstArg = init.arguments[0]

    if (!firstArg || !ts.isIdentifier(firstArg)) {
      continue
    }

    const targetTable = firstArg.text

    const secondArg = init.arguments[1]

    if (callee === "many") {
      let aliasExpr: ts.Expression | undefined
      let extraConfigProps: ts.ObjectLiteralElementLike[] | undefined

      if (secondArg && ts.isObjectLiteralExpression(secondArg)) {
        const {
          alias, otherProps,
        } = mapConfigObject(secondArg)

        aliasExpr = alias
        extraConfigProps = otherProps.length
          ? otherProps
          : undefined
      }

      out.push({
        kind: "many", propName, targetTable, aliasExpr, extraConfigProps,
      })
    }

    if (callee === "one") {
      let from: ts.Expression | undefined
      let to: ts.Expression | undefined
      let aliasExpr: ts.Expression | undefined
      let extraConfigProps: ts.ObjectLiteralElementLike[] | undefined

      if (secondArg && ts.isObjectLiteralExpression(secondArg)) {
        const mapped = mapConfigObject(secondArg)

        from = mapped.from
        to = mapped.to
        aliasExpr = mapped.alias
        extraConfigProps = mapped.otherProps.length
          ? mapped.otherProps
          : undefined
      }

      out.push({
        kind: "one", propName, targetTable, from, to, aliasExpr, extraConfigProps,
      })
    }
  }

  return out
}

function buildV2RelationProp(rp: V1RelationProp): ts.PropertyAssignment {
  // r.one.users({ from: ..., to: ..., alias?: ... })
  // r.many.posts() or r.many.posts({ alias?: ... })
  const base = f.createPropertyAccessExpression(
    f.createPropertyAccessExpression(f.createIdentifier("r"), f.createIdentifier(rp.kind)),
    f.createIdentifier(rp.targetTable),
  )

  if (rp.kind === "many") {
    // If we have config bits we understand, pass them through; otherwise just ()
    const configProps: ts.ObjectLiteralElementLike[] = []

    if (rp.aliasExpr) {
      configProps.push(f.createPropertyAssignment("alias", rp.aliasExpr))
    }

    if (rp.extraConfigProps?.length) {
      configProps.push(...rp.extraConfigProps)
    }

    const call = configProps.length
      ? f.createCallExpression(base, undefined, [f.createObjectLiteralExpression(configProps, true)])
      : f.createCallExpression(base, undefined, [])

    return f.createPropertyAssignment(rp.propName, call)
  }

  // one
  const configProps: ts.ObjectLiteralElementLike[] = []

  if (rp.from) {
    configProps.push(f.createPropertyAssignment("from", rp.from))
  }

  if (rp.to) {
    configProps.push(f.createPropertyAssignment("to", rp.to))
  }

  if (rp.aliasExpr) {
    configProps.push(f.createPropertyAssignment("alias", rp.aliasExpr))
  }

  if (rp.extraConfigProps?.length) {
    configProps.push(...rp.extraConfigProps)
  }

  const call = f.createCallExpression(base, undefined, [f.createObjectLiteralExpression(configProps, true)])

  return f.createPropertyAssignment(rp.propName, call)
}

// ---------- collect tables & v1 relation blocks ----------

const tableNames: string[] = []
const v1RelationsByTable = new Map<string, V1RelationProp[]>()

for (const st of sf.statements) {
  if (isSqliteTableDecl(st)) {
    const decl = st.declarationList.declarations[0]!

    // oxlint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
    tableNames.push((decl.name as ts.Identifier).text)
  }

  if (isRelationsConstDecl(st)) {
    const decl = st.declarationList.declarations[0]!
    // oxlint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
    const init = decl.initializer as ts.CallExpression

    const tableArg = init.arguments[0]
    const cbArg = init.arguments[1]

    if (!tableArg || !ts.isIdentifier(tableArg)) {
      continue
    }

    const tableName = tableArg.text

    // Expect callback returning object literal : ({ one, many }) => ({ ... })
    if (!cbArg || !(ts.isArrowFunction(cbArg) || ts.isFunctionExpression(cbArg))) {
      continue
    }

    const body = cbArg.body
    const returned
      = ts.isBlock(body)
        ? body.statements.find((s) => ts.isReturnStatement(s))
        // oxlint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
        && (body.statements.find((s) => ts.isReturnStatement(s)) as ts.ReturnStatement).expression
        : body

    if (!returned || (!ts.isParenthesizedExpression(returned) && !ts.isObjectLiteralExpression(returned))) {
      continue
    }

    const obj = ts.isObjectLiteralExpression(returned)
      ? returned
      : ts.isParenthesizedExpression(returned) && ts.isObjectLiteralExpression(returned.expression)
        ? returned.expression
        : undefined

    if (!obj) {
      continue
    }

    const parsed = parseV1RelationsObject(obj)

    if (parsed.length) {
      v1RelationsByTable.set(tableName, parsed)
    }
  }
}

// ---------- build new statements ----------

function updateDrizzleOrmImport(stmt: ts.Statement): ts.Statement {
  if (!ts.isImportDeclaration(stmt)) {
    return stmt
  }

  if (!ts.isStringLiteral(stmt.moduleSpecifier)) {
    return stmt
  }

  if (stmt.moduleSpecifier.text !== "drizzle-orm") {
    return stmt
  }

  if (!stmt.importClause?.namedBindings || !ts.isNamedImports(stmt.importClause.namedBindings)) {
    return stmt
  }

  const named = stmt.importClause.namedBindings
  const elems = named.elements

  let hasDefineRelations = false
  const newElems: ts.ImportSpecifier[] = []

  for (const e of elems) {
    const imported = e.propertyName
      ? e.propertyName.text
      : e.name.text

    if (imported === "relations") {
      // drop v1 relations import
      continue
    }

    if (imported === "defineRelations") {
      hasDefineRelations = true
    }

    newElems.push(e)
  }

  if (!hasDefineRelations) {
    newElems.push(f.createImportSpecifier(false, undefined, f.createIdentifier("defineRelations")))
  }

  const phaseModifier = stmt.importClause.phaseModifier

  const newImportClause = f.createImportClause(
    phaseModifier,
    stmt.importClause.name,
    f.createNamedImports(newElems),
  )

  // oxlint-disable-next-line @typescript-eslint/no-unsafe-type-assertion
  const attributes = (stmt as any).attributes

  return f.updateImportDeclaration(
    stmt,
    stmt.modifiers,
    newImportClause,
    stmt.moduleSpecifier,
    attributes,
  )
}

const schemaConstStmt = f.createVariableStatement(
  undefined,
  f.createVariableDeclarationList(
    [
      f.createVariableDeclaration(
        "schema",
        undefined,
        undefined,
        f.createAsExpression(
          f.createObjectLiteralExpression(
            tableNames.map((n) => f.createShorthandPropertyAssignment(n)),
            true,
          ),
          f.createTypeReferenceNode("const"),
        ),
      ),
    ],
    ts.NodeFlags.Const,
  ),
)

const relationsObjectProps: ts.PropertyAssignment[] = []

for (const [ tableName, rels ] of v1RelationsByTable.entries()) {
  const v2Props = rels.map(buildV2RelationProp)

  relationsObjectProps.push(f.createPropertyAssignment(tableName, f.createObjectLiteralExpression(v2Props, true)))
}

const defineRelationsStmt = f.createVariableStatement(
  [f.createModifier(ts.SyntaxKind.ExportKeyword)],
  f.createVariableDeclarationList(
    [
      f.createVariableDeclaration(
        "relations",
        undefined,
        undefined,
        f.createCallExpression(f.createIdentifier("defineRelations"), undefined, [
          f.createIdentifier("schema"),
          f.createArrowFunction(
            undefined,
            undefined,
            [f.createParameterDeclaration(undefined, undefined, "r", undefined, undefined, undefined)],
            undefined,
            f.createToken(ts.SyntaxKind.EqualsGreaterThanToken),
            f.createParenthesizedExpression(f.createObjectLiteralExpression(relationsObjectProps, true)),
          ),
        ]),
      ),
    ],
    ts.NodeFlags.Const,
  ),
)

// ---------- rewrite file statements ----------

const newStatements: ts.Statement[] = []
let insertedNewRelationsBlock = false

for (const st of sf.statements) {
  // 1) Update drizzle-orm import
  const updated = updateDrizzleOrmImport(st)

  // 2) Remove old exported relations consts
  if (isRelationsConstDecl(updated)) {
    continue
  }

  newStatements.push(updated)

  // 3) Insert schema+defineRelations after the last sqliteTable declaration block
  // We do this once, right after we pass the last table definition
  // Heuristic : insert after we see the last exported sqliteTable statement
  if (!insertedNewRelationsBlock) {
    // Look ahead : if there are no more sqliteTable decls after this statement, insert here
    const _idx = newStatements.length - 1
    const originalIdx = sf.statements.indexOf(st)
    const remaining = sf.statements.slice(originalIdx + 1)
    const hasMoreTables = remaining.some((x) => isSqliteTableDecl(x))

    if (isSqliteTableDecl(st) && !hasMoreTables) {
      // spacer for printer stability
      newStatements.push(f.createEmptyStatement())
      newStatements.push(schemaConstStmt)
      newStatements.push(f.createEmptyStatement())
      newStatements.push(defineRelationsStmt)
      insertedNewRelationsBlock = true
    }
  }
}

// If file had no sqliteTable blocks (unlikely), just append
if (!insertedNewRelationsBlock) {
  newStatements.push(schemaConstStmt, defineRelationsStmt)
}

const outSf = f.updateSourceFile(sf, newStatements.filter((s) => s.kind !== ts.SyntaxKind.NotEmittedStatement))

const printer = ts.createPrinter({
  newLine: ts.NewLineKind.LineFeed,
  removeComments: false,
})

const result = printer.printFile(outSf)

// ---------- output ----------

if (shouldWrite) {
  fs.writeFileSync(filePath, result, "utf8")
  console.log(`Updated ${path.relative(process.cwd(), filePath)}`)
} else {
  console.log(result)
}

@EDM115 commented on GitHub (Jan 31, 2026): for anyone interested, I wrote a "codemod-like" script to make the better-auth cli generated schema to be compatible with drizzle v2 relational queries, although this is a band-aid : ```ts /* oxlint-disable @typescript-eslint/no-explicit-any */ import fs from "node:fs" import path from "node:path" import ts from "typescript" /** * Example usage : tsx shared/db/fix-auth-relations.codemod.ts shared/db/auth.schema.ts --write * Without --write, prints the transformed file to stdout */ const argv = process.argv.slice(2) const filePathArg = argv.find((a) => !a.startsWith("--")) ?? "shared/db/auth.schema.ts" const shouldWrite = argv.includes("--write") const filePath = path.resolve(process.cwd(), filePathArg) const input = fs.readFileSync(filePath, "utf8") const sf = ts.createSourceFile(filePath, input, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS) // ---------- helpers ---------- const f = ts.factory function isCall(node: ts.Node, name: string): node is ts.CallExpression { return ts.isCallExpression(node) && ts.isIdentifier(node.expression) && node.expression.text === name } function isSqliteTableDecl(stmt: ts.Statement): stmt is ts.VariableStatement { if (!ts.isVariableStatement(stmt)) { return false } if (!stmt.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)) { return false } const decl = stmt.declarationList.declarations[0] if (!decl || !ts.isIdentifier(decl.name) || !decl.initializer) { return false } return ts.isCallExpression(decl.initializer) && ts.isIdentifier(decl.initializer.expression) ? decl.initializer.expression.text === "sqliteTable" : false } function isRelationsConstDecl(stmt: ts.Statement): stmt is ts.VariableStatement { if (!ts.isVariableStatement(stmt)) { return false } if (!stmt.modifiers?.some((m) => m.kind === ts.SyntaxKind.ExportKeyword)) { return false } const decl = stmt.declarationList.declarations[0] if (!decl || !ts.isIdentifier(decl.name) || !decl.initializer) { return false } return isCall(decl.initializer, "relations") } function unwrapSingleArray(expr: ts.Expression): ts.Expression { if (ts.isArrayLiteralExpression(expr) && expr.elements.length === 1) { const el = expr.elements[0] if (!el) { return expr } return ts.isSpreadElement(el) ? expr : el } return expr } function toRColumn(expr: ts.Expression): ts.Expression { // Convert : table.column -> r.table.column // Keep everything else as-is if (ts.isPropertyAccessExpression(expr) && ts.isIdentifier(expr.expression)) { const tableName = expr.expression.text const colName = expr.name.text return f.createPropertyAccessExpression( f.createPropertyAccessExpression(f.createIdentifier("r"), f.createIdentifier(tableName)), f.createIdentifier(colName), ) } // Also handle nested forms like : someAlias.userId? // We only rewrite identifier.property return expr } function mapConfigObject(obj: ts.ObjectLiteralExpression): { from?: ts.Expression; to?: ts.Expression; alias?: ts.Expression; otherProps: ts.ObjectLiteralElementLike[]; } { let from: ts.Expression | undefined let to: ts.Expression | undefined let alias: ts.Expression | undefined const otherProps: ts.ObjectLiteralElementLike[] = [] for (const prop of obj.properties) { if (!ts.isPropertyAssignment(prop) || !ts.isIdentifier(prop.name)) { otherProps.push(prop) continue } const key = prop.name.text const value = prop.initializer if (key === "fields") { // fields : [session.userId] -> from: r.session.userId const v = unwrapSingleArray(value) from = ts.isArrayLiteralExpression(v) ? f.createArrayLiteralExpression(v.elements.map((e) => toRColumn(e))) : toRColumn(v) continue } if (key === "references") { // references : [user.id] -> to: r.user.id const v = unwrapSingleArray(value) to = ts.isArrayLiteralExpression(v) ? f.createArrayLiteralExpression(v.elements.map((e) => toRColumn(e))) : toRColumn(v) continue } if (key === "relationName") { // relationName -> alias alias = value continue } // keep any unknown config options (future-proof) otherProps.push(prop) } return { from, to, alias, otherProps, } } type V1RelationProp = | { kind: "many"; propName: string; targetTable: string; aliasExpr?: ts.Expression; extraConfigProps?: ts.ObjectLiteralElementLike[]; } | { kind: "one"; propName: string; targetTable: string; from?: ts.Expression; to?: ts.Expression; aliasExpr?: ts.Expression; extraConfigProps?: ts.ObjectLiteralElementLike[]; } function parseV1RelationsObject(obj: ts.ObjectLiteralExpression): V1RelationProp[] { const out: V1RelationProp[] = [] for (const p of obj.properties) { if (!ts.isPropertyAssignment(p)) { continue } const propName = ts.isIdentifier(p.name) ? p.name.text : ts.isStringLiteral(p.name) ? p.name.text : undefined if (!propName) { continue } const init = p.initializer if (!ts.isCallExpression(init) || !ts.isIdentifier(init.expression)) { continue } // "many" | "one" const callee = init.expression.text const firstArg = init.arguments[0] if (!firstArg || !ts.isIdentifier(firstArg)) { continue } const targetTable = firstArg.text const secondArg = init.arguments[1] if (callee === "many") { let aliasExpr: ts.Expression | undefined let extraConfigProps: ts.ObjectLiteralElementLike[] | undefined if (secondArg && ts.isObjectLiteralExpression(secondArg)) { const { alias, otherProps, } = mapConfigObject(secondArg) aliasExpr = alias extraConfigProps = otherProps.length ? otherProps : undefined } out.push({ kind: "many", propName, targetTable, aliasExpr, extraConfigProps, }) } if (callee === "one") { let from: ts.Expression | undefined let to: ts.Expression | undefined let aliasExpr: ts.Expression | undefined let extraConfigProps: ts.ObjectLiteralElementLike[] | undefined if (secondArg && ts.isObjectLiteralExpression(secondArg)) { const mapped = mapConfigObject(secondArg) from = mapped.from to = mapped.to aliasExpr = mapped.alias extraConfigProps = mapped.otherProps.length ? mapped.otherProps : undefined } out.push({ kind: "one", propName, targetTable, from, to, aliasExpr, extraConfigProps, }) } } return out } function buildV2RelationProp(rp: V1RelationProp): ts.PropertyAssignment { // r.one.users({ from: ..., to: ..., alias?: ... }) // r.many.posts() or r.many.posts({ alias?: ... }) const base = f.createPropertyAccessExpression( f.createPropertyAccessExpression(f.createIdentifier("r"), f.createIdentifier(rp.kind)), f.createIdentifier(rp.targetTable), ) if (rp.kind === "many") { // If we have config bits we understand, pass them through; otherwise just () const configProps: ts.ObjectLiteralElementLike[] = [] if (rp.aliasExpr) { configProps.push(f.createPropertyAssignment("alias", rp.aliasExpr)) } if (rp.extraConfigProps?.length) { configProps.push(...rp.extraConfigProps) } const call = configProps.length ? f.createCallExpression(base, undefined, [f.createObjectLiteralExpression(configProps, true)]) : f.createCallExpression(base, undefined, []) return f.createPropertyAssignment(rp.propName, call) } // one const configProps: ts.ObjectLiteralElementLike[] = [] if (rp.from) { configProps.push(f.createPropertyAssignment("from", rp.from)) } if (rp.to) { configProps.push(f.createPropertyAssignment("to", rp.to)) } if (rp.aliasExpr) { configProps.push(f.createPropertyAssignment("alias", rp.aliasExpr)) } if (rp.extraConfigProps?.length) { configProps.push(...rp.extraConfigProps) } const call = f.createCallExpression(base, undefined, [f.createObjectLiteralExpression(configProps, true)]) return f.createPropertyAssignment(rp.propName, call) } // ---------- collect tables & v1 relation blocks ---------- const tableNames: string[] = [] const v1RelationsByTable = new Map<string, V1RelationProp[]>() for (const st of sf.statements) { if (isSqliteTableDecl(st)) { const decl = st.declarationList.declarations[0]! // oxlint-disable-next-line @typescript-eslint/no-unsafe-type-assertion tableNames.push((decl.name as ts.Identifier).text) } if (isRelationsConstDecl(st)) { const decl = st.declarationList.declarations[0]! // oxlint-disable-next-line @typescript-eslint/no-unsafe-type-assertion const init = decl.initializer as ts.CallExpression const tableArg = init.arguments[0] const cbArg = init.arguments[1] if (!tableArg || !ts.isIdentifier(tableArg)) { continue } const tableName = tableArg.text // Expect callback returning object literal : ({ one, many }) => ({ ... }) if (!cbArg || !(ts.isArrowFunction(cbArg) || ts.isFunctionExpression(cbArg))) { continue } const body = cbArg.body const returned = ts.isBlock(body) ? body.statements.find((s) => ts.isReturnStatement(s)) // oxlint-disable-next-line @typescript-eslint/no-unsafe-type-assertion && (body.statements.find((s) => ts.isReturnStatement(s)) as ts.ReturnStatement).expression : body if (!returned || (!ts.isParenthesizedExpression(returned) && !ts.isObjectLiteralExpression(returned))) { continue } const obj = ts.isObjectLiteralExpression(returned) ? returned : ts.isParenthesizedExpression(returned) && ts.isObjectLiteralExpression(returned.expression) ? returned.expression : undefined if (!obj) { continue } const parsed = parseV1RelationsObject(obj) if (parsed.length) { v1RelationsByTable.set(tableName, parsed) } } } // ---------- build new statements ---------- function updateDrizzleOrmImport(stmt: ts.Statement): ts.Statement { if (!ts.isImportDeclaration(stmt)) { return stmt } if (!ts.isStringLiteral(stmt.moduleSpecifier)) { return stmt } if (stmt.moduleSpecifier.text !== "drizzle-orm") { return stmt } if (!stmt.importClause?.namedBindings || !ts.isNamedImports(stmt.importClause.namedBindings)) { return stmt } const named = stmt.importClause.namedBindings const elems = named.elements let hasDefineRelations = false const newElems: ts.ImportSpecifier[] = [] for (const e of elems) { const imported = e.propertyName ? e.propertyName.text : e.name.text if (imported === "relations") { // drop v1 relations import continue } if (imported === "defineRelations") { hasDefineRelations = true } newElems.push(e) } if (!hasDefineRelations) { newElems.push(f.createImportSpecifier(false, undefined, f.createIdentifier("defineRelations"))) } const phaseModifier = stmt.importClause.phaseModifier const newImportClause = f.createImportClause( phaseModifier, stmt.importClause.name, f.createNamedImports(newElems), ) // oxlint-disable-next-line @typescript-eslint/no-unsafe-type-assertion const attributes = (stmt as any).attributes return f.updateImportDeclaration( stmt, stmt.modifiers, newImportClause, stmt.moduleSpecifier, attributes, ) } const schemaConstStmt = f.createVariableStatement( undefined, f.createVariableDeclarationList( [ f.createVariableDeclaration( "schema", undefined, undefined, f.createAsExpression( f.createObjectLiteralExpression( tableNames.map((n) => f.createShorthandPropertyAssignment(n)), true, ), f.createTypeReferenceNode("const"), ), ), ], ts.NodeFlags.Const, ), ) const relationsObjectProps: ts.PropertyAssignment[] = [] for (const [ tableName, rels ] of v1RelationsByTable.entries()) { const v2Props = rels.map(buildV2RelationProp) relationsObjectProps.push(f.createPropertyAssignment(tableName, f.createObjectLiteralExpression(v2Props, true))) } const defineRelationsStmt = f.createVariableStatement( [f.createModifier(ts.SyntaxKind.ExportKeyword)], f.createVariableDeclarationList( [ f.createVariableDeclaration( "relations", undefined, undefined, f.createCallExpression(f.createIdentifier("defineRelations"), undefined, [ f.createIdentifier("schema"), f.createArrowFunction( undefined, undefined, [f.createParameterDeclaration(undefined, undefined, "r", undefined, undefined, undefined)], undefined, f.createToken(ts.SyntaxKind.EqualsGreaterThanToken), f.createParenthesizedExpression(f.createObjectLiteralExpression(relationsObjectProps, true)), ), ]), ), ], ts.NodeFlags.Const, ), ) // ---------- rewrite file statements ---------- const newStatements: ts.Statement[] = [] let insertedNewRelationsBlock = false for (const st of sf.statements) { // 1) Update drizzle-orm import const updated = updateDrizzleOrmImport(st) // 2) Remove old exported relations consts if (isRelationsConstDecl(updated)) { continue } newStatements.push(updated) // 3) Insert schema+defineRelations after the last sqliteTable declaration block // We do this once, right after we pass the last table definition // Heuristic : insert after we see the last exported sqliteTable statement if (!insertedNewRelationsBlock) { // Look ahead : if there are no more sqliteTable decls after this statement, insert here const _idx = newStatements.length - 1 const originalIdx = sf.statements.indexOf(st) const remaining = sf.statements.slice(originalIdx + 1) const hasMoreTables = remaining.some((x) => isSqliteTableDecl(x)) if (isSqliteTableDecl(st) && !hasMoreTables) { // spacer for printer stability newStatements.push(f.createEmptyStatement()) newStatements.push(schemaConstStmt) newStatements.push(f.createEmptyStatement()) newStatements.push(defineRelationsStmt) insertedNewRelationsBlock = true } } } // If file had no sqliteTable blocks (unlikely), just append if (!insertedNewRelationsBlock) { newStatements.push(schemaConstStmt, defineRelationsStmt) } const outSf = f.updateSourceFile(sf, newStatements.filter((s) => s.kind !== ts.SyntaxKind.NotEmittedStatement)) const printer = ts.createPrinter({ newLine: ts.NewLineKind.LineFeed, removeComments: false, }) const result = printer.printFile(outSf) // ---------- output ---------- if (shouldWrite) { fs.writeFileSync(filePath, result, "utf8") console.log(`Updated ${path.relative(process.cwd(), filePath)}`) } else { console.log(result) } ```
Author
Owner

@fax1ty commented on GitHub (Feb 7, 2026):

For anyone using this before it's merged, make sure to also use the PR's CLI version too:

  • npx @better-auth/cli@latest generate

[#better-auth]: Couldn't read your auth config. Error: Cannot find module 'bun:sqlite'

Not suitable for Bun SQLite

@fax1ty commented on GitHub (Feb 7, 2026): > For anyone using this before it's merged, make sure to also use the PR's CLI version too: > > - npx @better-auth/cli@latest generate > + pnpx https://pkg.pr.new/better-auth/better-auth/@better-auth/cli@6913 generate [#better-auth]: Couldn't read your auth config. Error: Cannot find module 'bun:sqlite' Not suitable for Bun SQLite
Author
Owner

@ping-maxwell commented on GitHub (Feb 10, 2026):

For anyone using this before it's merged, make sure to also use the PR's CLI version too:

[#better-auth]: Couldn't read your auth config. Error: Cannot find module 'bun:sqlite'

Not suitable for Bun SQLite

did you try with bunx?

@ping-maxwell commented on GitHub (Feb 10, 2026): > > For anyone using this before it's merged, make sure to also use the PR's CLI version too: > > > > * npx @better-auth/cli@latest generate > > > > > > * pnpx [pkg.pr.new/better-auth/better-auth/@better-auth/cli@6913](https://pkg.pr.new/better-auth/better-auth/@better-auth/cli@6913) generate > > [#better-auth]: Couldn't read your auth config. Error: Cannot find module 'bun:sqlite' > > Not suitable for Bun SQLite did you try with `bunx`?
Author
Owner

@DallasHoff commented on GitHub (Mar 3, 2026):

I tested the PR packages. Here's what I ran into.

  • The peer dependency entry for drizzle-orm is still ">=0.41.0" so the package manager has to be forced to install the PR packages when Drizzle v1 is installed.
  • Generating the schema deleted the definition for the verification table.
  • The generated relations still use defineRelations, not defineRelationsPart.
@DallasHoff commented on GitHub (Mar 3, 2026): I tested the PR packages. Here's what I ran into. - The peer dependency entry for drizzle-orm is still ">=0.41.0" so the package manager has to be forced to install the PR packages when Drizzle v1 is installed. - Generating the schema deleted the definition for the `verification` table. - The generated relations still use `defineRelations`, not `defineRelationsPart`.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#2532