[GH-ISSUE #3549] Make the CLI generator more flexible (no need to read auth.ts) #18271

Closed
opened 2026-04-15 16:41:36 -05:00 by GiteaMirror · 5 comments
Owner

Originally created by @ericc-ch on GitHub (Jul 22, 2025).
Original GitHub issue: https://github.com/better-auth/better-auth/issues/3549

Is this suited for github?

  • Yes, this is suited for github

Is your feature request related to a problem? Please describe.

I want to generate better-auth schema for Drizzle + D1. But the way I write the auth service makes the CLI cannot find it.

import { betterAuth } from "better-auth"
import { drizzleAdapter } from "better-auth/adapters/drizzle"
import { Effect } from "effect"

import { Database } from "./database"

export class Auth extends Effect.Service<Auth>()("service/Auth", {
  effect: Effect.gen(function* () {
    const db = yield* Database
    return betterAuth({
      database: drizzleAdapter(db, { provider: "sqlite" }),
    })
  }),
}) {}

Image

Pretty similar problem to this issue
https://github.com/better-auth/better-auth/issues/1272

Describe the solution you'd like

I think we can either:

  1. Make the CLI interactive. Choosing options after running generate
  2. Add more CLI flags so that using auth.ts or --config is optional. For example, --database, --adapter, --provider, etc. (These are just example flags)

Describe alternatives you've considered

I've tried writing temporary auth.ts file but it's not the most ergonomic solution

Additional context

I can try to open a PR for this :)

Originally created by @ericc-ch on GitHub (Jul 22, 2025). Original GitHub issue: https://github.com/better-auth/better-auth/issues/3549 ### Is this suited for github? - [x] Yes, this is suited for github ### Is your feature request related to a problem? Please describe. I want to generate better-auth schema for Drizzle + D1. But the way I write the auth service makes the CLI cannot find it. ```typescript import { betterAuth } from "better-auth" import { drizzleAdapter } from "better-auth/adapters/drizzle" import { Effect } from "effect" import { Database } from "./database" export class Auth extends Effect.Service<Auth>()("service/Auth", { effect: Effect.gen(function* () { const db = yield* Database return betterAuth({ database: drizzleAdapter(db, { provider: "sqlite" }), }) }), }) {} ``` <img width="1448" height="187" alt="Image" src="https://github.com/user-attachments/assets/c825d376-f5df-4b24-92bb-2e27f3df331d" /> Pretty similar problem to this issue https://github.com/better-auth/better-auth/issues/1272 ### Describe the solution you'd like I think we can either: 1. Make the CLI interactive. Choosing options after running `generate` 2. Add more CLI flags so that using `auth.ts` or `--config` is optional. For example, `--database`, `--adapter`, `--provider`, etc. (These are just example flags) ### Describe alternatives you've considered I've tried writing temporary `auth.ts` file but it's not the most ergonomic solution ### Additional context I can try to open a PR for this :)
GiteaMirror added the lockedenhancement labels 2026-04-15 16:41:37 -05:00
Author
Owner

@taylorcode commented on GitHub (Jul 25, 2025):

in case others hit this, I was able to generate the appropriate create table queries for my cloudflare D1 database with:

  1. npm install better-sqlite3
  2. npm rebuild better-sqlite3
  3. create this file (auth.ts):
import {betterAuth} from 'better-auth';
import Database from 'better-sqlite3';

export const auth = betterAuth({
  database: new Database('./sqlite.db'),
});
  1. run:
    npx @better-auth/cli generate. Optionally provide a path for the auth.ts file via the config flag --config ./some/path/auth.ts.

This generated a file at the path ./better-auth_migrations/2025-07-25T19-35-51.472Z.sql containing the queries, and I executed these on my D1 database in the cloudflare console.

<!-- gh-comment-id:3120160469 --> @taylorcode commented on GitHub (Jul 25, 2025): in case others hit this, I was able to generate the appropriate `create table` queries for my cloudflare D1 database with: 1. `npm install better-sqlite3` 2. `npm rebuild better-sqlite3` 3. create this file (`auth.ts`): ``` import {betterAuth} from 'better-auth'; import Database from 'better-sqlite3'; export const auth = betterAuth({ database: new Database('./sqlite.db'), }); ``` 4. run: `npx @better-auth/cli generate`. Optionally provide a path for the `auth.ts` file via the config flag `--config ./some/path/auth.ts`. This generated a file at the path `./better-auth_migrations/2025-07-25T19-35-51.472Z.sql` containing the queries, and I executed these on my D1 database in the cloudflare console.
Author
Owner

@ping-maxwell commented on GitHub (Jul 30, 2025):

It would only be able to cater things from Better-Auth, but the moment the user uses anything that's not in-house this solution wouldn't work. For example, some adapters and some plugins are not from Better-Auth, so the CLI wouldn't be able to resolve the data when passed through the CLI flags in those cases.

Not too sure about this idea 🤔

<!-- gh-comment-id:3135936669 --> @ping-maxwell commented on GitHub (Jul 30, 2025): It would only be able to cater things from Better-Auth, but the moment the user uses anything that's not in-house this solution wouldn't work. For example, some adapters and some plugins are not from Better-Auth, so the CLI wouldn't be able to resolve the data when passed through the CLI flags in those cases. Not too sure about this idea 🤔
Author
Owner

@ericc-ch commented on GitHub (Jul 31, 2025):

I just realized this is a Cloudflare specific issue, since D1 binding is passed through fetch handler. Otherwise using the generate command with --config or re-export would be fine. I even stumbled into a solution since I'm using Effect.

I also read the code for schema generation. I didn't realize the codegen respects betterAuth() options. Thank you @ping-maxwell for pointing that out.

What I've tried so far:

import { D1Client } from "@effect/sql-d1"
import { betterAuth } from "better-auth"
import { drizzleAdapter } from "better-auth/adapters/drizzle"
import { Effect, pipe } from "effect"

import { Database } from "./database"

export class Auth extends Effect.Service<Auth>()("service/Auth", {
  effect: Effect.gen(function* () {
    const db = yield* Database
    return betterAuth({
      database: drizzleAdapter(db, { provider: "sqlite" }),
    })
  }),
}) {}

// Maybe exporting a function that returns auth instance 
export const getAuth = () => {
  const getConfig = Effect.gen(function* () {
    return yield* Auth
  })

  const betterAuth = pipe(
    getConfig,
    Effect.provide(Auth.Default),
    Effect.provide(Database.Default),
    // But I still cannot actually pass the db here
    Effect.provide(D1Client.layer({ db })), // db is undefined
    Effect.runSync,
  )

  return betterAuth
}


// But because I use Effect, I can just do
export const auth = Auth.Service


Instead, I ran into a different issue this time

Image

I think this is because my root tsconfig.json doesn't contain any path aliases

{
  "compilerOptions": {
    "target": "ES2022",
    "skipLibCheck": true,
    "allowJs": true,

    "module": "ES2022",
    "moduleResolution": "bundler",
    "erasableSyntaxOnly": true,
    "verbatimModuleSyntax": true,
    "noEmit": true,

    "strict": true,
    "noUnusedLocals": true,
    "noUnusedParameters": true,
    "exactOptionalPropertyTypes": true,
    "noFallthroughCasesInSwitch": true,
    "noUncheckedSideEffectImports": true,

    "types": ["./worker-configuration.d.ts"],

    "plugins": [
      {
        "name": "@effect/language-service"
      }
    ]
  },

  "references": [
    { "path": "./tsconfig.app.json" },
    { "path": "./tsconfig.test.json" },
    { "path": "./tsconfig.node.json" }
  ],

  "files": []
}

<!-- gh-comment-id:3138264470 --> @ericc-ch commented on GitHub (Jul 31, 2025): I just realized this is a Cloudflare specific issue, since D1 binding is passed through fetch handler. Otherwise using the `generate` command with `--config` or re-export would be fine. I even stumbled into a solution since I'm using Effect. I also read the code for schema generation. I didn't realize the codegen respects `betterAuth()` options. Thank you @ping-maxwell for pointing that out. What I've tried so far: ```typescript import { D1Client } from "@effect/sql-d1" import { betterAuth } from "better-auth" import { drizzleAdapter } from "better-auth/adapters/drizzle" import { Effect, pipe } from "effect" import { Database } from "./database" export class Auth extends Effect.Service<Auth>()("service/Auth", { effect: Effect.gen(function* () { const db = yield* Database return betterAuth({ database: drizzleAdapter(db, { provider: "sqlite" }), }) }), }) {} // Maybe exporting a function that returns auth instance export const getAuth = () => { const getConfig = Effect.gen(function* () { return yield* Auth }) const betterAuth = pipe( getConfig, Effect.provide(Auth.Default), Effect.provide(Database.Default), // But I still cannot actually pass the db here Effect.provide(D1Client.layer({ db })), // db is undefined Effect.runSync, ) return betterAuth } // But because I use Effect, I can just do export const auth = Auth.Service ``` --- Instead, I ran into a different issue this time <img width="1137" height="425" alt="Image" src="https://github.com/user-attachments/assets/c67d6175-5f0d-4ecc-910e-7b1a0b0a7408" /> I think this is because my root `tsconfig.json` doesn't contain any path aliases ```jsonc { "compilerOptions": { "target": "ES2022", "skipLibCheck": true, "allowJs": true, "module": "ES2022", "moduleResolution": "bundler", "erasableSyntaxOnly": true, "verbatimModuleSyntax": true, "noEmit": true, "strict": true, "noUnusedLocals": true, "noUnusedParameters": true, "exactOptionalPropertyTypes": true, "noFallthroughCasesInSwitch": true, "noUncheckedSideEffectImports": true, "types": ["./worker-configuration.d.ts"], "plugins": [ { "name": "@effect/language-service" } ] }, "references": [ { "path": "./tsconfig.app.json" }, { "path": "./tsconfig.test.json" }, { "path": "./tsconfig.node.json" } ], "files": [] } ```
Author
Owner

@ping-maxwell commented on GitHub (Jul 31, 2025):

Usually I recommend making a "fake" auth.ts with the soul purpose of exporting a auth using betterAuth without the wrapper function that something like Cloudflare D1 requires.

<!-- gh-comment-id:3138334941 --> @ping-maxwell commented on GitHub (Jul 31, 2025): Usually I recommend making a "fake" auth.ts with the soul purpose of exporting a `auth` using `betterAuth` without the wrapper function that something like Cloudflare D1 requires.
Author
Owner

@ericc-ch commented on GitHub (Jul 31, 2025):

Yeah thank you @ping-maxwell, I think that's the best approach for now. Also thank you for taking your time to respond to all of my messages.

Good luck to you and the rest of better-auth team! You guys are making such an awesome library

<!-- gh-comment-id:3138402346 --> @ericc-ch commented on GitHub (Jul 31, 2025): Yeah thank you @ping-maxwell, I think that's the best approach for now. Also thank you for taking your time to respond to all of my messages. Good luck to you and the rest of better-auth team! You guys are making such an awesome library
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: github-starred/better-auth#18271