How to use better-auth CLI in a Cloudflare workers + Cloudflare D1 + react-router + drizzle project?

I created a React Router 7 project using the Cloudflare workers template: pnpm create cloudflare@latest my-react-router-app --framework=react-router . I added D1 bindings and drizzle to this project. The Problem: I am struggling to find a pattern where I can somehow export auth in a way the CLI can pick up. The crux is that betterAuth() requires the db instance as a function argument. In Cloudlfare workers, however, the db instance is only available in the fetch() function. So logically the only spot I can instance the drizzle ORM db instance, and thus the betterAuth instance, is within the fetch function scope. The question is: is there a work around to this? I can't be the first to run into this little puzzle. Let me know any ideas! Note: I am aware of a way to import the env globally by import { env } from "cloudflare:workers";, however this package is only available in a Cloudflare or Miniflare environment. Ref: https://developers.cloudflare.com/changelog/2025-03-17-importable-env/
import { createRequestHandler } from "react-router";
import { drizzle, type DrizzleD1Database } from "drizzle-orm/d1";
import { betterAuth } from "better-auth";
import * as schema from '../database/schema'
import { drizzleAdapter } from "better-auth/adapters/drizzle";

declare module "react-router" {
export interface AppLoadContext {
db: DrizzleD1Database<typeof schema>,
cloudflare: {
env: Env;
ctx: ExecutionContext;
};
}
}

const requestHandler = createRequestHandler(
() => import("virtual:react-router/server-build"),
import.meta.env.MODE
);

export default {
async fetch(request, env, ctx) {
const db = drizzle(env.DB, { schema });
// Better Auth CLI cannot reach this:
const auth = betterAuth({
database: drizzleAdapter(db, {
provider: "sqlite",
})
});
return requestHandler(request, {
db,
cloudflare: { env, ctx },
});
},
} satisfies ExportedHandler<Env>;
import { createRequestHandler } from "react-router";
import { drizzle, type DrizzleD1Database } from "drizzle-orm/d1";
import { betterAuth } from "better-auth";
import * as schema from '../database/schema'
import { drizzleAdapter } from "better-auth/adapters/drizzle";

declare module "react-router" {
export interface AppLoadContext {
db: DrizzleD1Database<typeof schema>,
cloudflare: {
env: Env;
ctx: ExecutionContext;
};
}
}

const requestHandler = createRequestHandler(
() => import("virtual:react-router/server-build"),
import.meta.env.MODE
);

export default {
async fetch(request, env, ctx) {
const db = drizzle(env.DB, { schema });
// Better Auth CLI cannot reach this:
const auth = betterAuth({
database: drizzleAdapter(db, {
provider: "sqlite",
})
});
return requestHandler(request, {
db,
cloudflare: { env, ctx },
});
},
} satisfies ExportedHandler<Env>;
Solution:
I recommend making a fake auth file and a real auth file. The fake one is just your better-auth config except for any fields which require ENV vars. This file will be the one you would then use for the better-auth cli to read. The real one would be the one which includes all needed ENV variables for Better Auth to function....
Jump to solution
2 Replies
Solution
Ping
Ping3d ago
I recommend making a fake auth file and a real auth file. The fake one is just your better-auth config except for any fields which require ENV vars. This file will be the one you would then use for the better-auth cli to read. The real one would be the one which includes all needed ENV variables for Better Auth to function. Tip: Make a config which you can export and use between the both of the real & fake auth files, to keep things consistent - and of course, this excludes the ENV parts in this config.
true
trueOP3d ago
Gochya. Thanks for the response! I think that is a fine workaround. I simply did this to generate my tables:
// lib/auth.ts

import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { drizzle } from "drizzle-orm/libsql";

const mockDb = drizzle("file:mock.db");

export const auth = betterAuth({
database: drizzleAdapter(mockDb, {
provider: "sqlite",
}),
});
// lib/auth.ts

import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { drizzle } from "drizzle-orm/libsql";

const mockDb = drizzle("file:mock.db");

export const auth = betterAuth({
database: drizzleAdapter(mockDb, {
provider: "sqlite",
}),
});

Did you find this page helpful?