1---
2title: Cloudflare D1
3description: Deploy a Better Auth Worker with a native D1 database and automatic schema migrations.
4---
5
6This example creates a D1 database and a Worker serving Better Auth at `/api/auth`. It includes the auth configuration, database layer, and stack; no tutorial files are required.
7
8## Install
9
10```sh
11bun add @alchemy.run/better-auth better-auth@^1.7.5 kysely
12```
13
14`kysely` is the SQL adapter peer; D1 needs no separate database driver. Configure Cloudflare credentials through an [Alchemy profile](/environments/profiles) before deployment.
15
16## Define the Worker
17
18```typescript title="src/worker.ts"
19import { BetterAuth } from "@alchemy.run/better-auth";
20import { CloudflareD1 } from "@alchemy.run/better-auth/CloudflareD1";
21import * as Cloudflare from "alchemy/Cloudflare";
22import * as Effect from "effect/Effect";
23
24const AuthDb = Cloudflare.D1.Database("AuthDb");
25
26export default class AuthApi extends Cloudflare.Worker<AuthApi>()(
27 "AuthApi",
28 {
29 main: import.meta.url,
30 compatibility: { flags: ["nodejs_compat"] },
31 },
32 Effect.gen(function* () {
33 const auth = yield* BetterAuth({
34 basePath: "/api/auth",
35 emailAndPassword: { enabled: true },
36 });
37 return { fetch: auth.fetch };
38 }).pipe(Effect.provide(CloudflareD1(AuthDb))),
39) {}
40```
41
42`CloudflareD1` registers the native Worker binding and supplies Better Auth's database service. This auth-only Worker forwards every request to Better Auth; endpoints live under `/api/auth`.
43
44## Define the stack
45
46```typescript title="alchemy.run.ts"
47import * as Alchemy from "alchemy";
48import * as Cloudflare from "alchemy/Cloudflare";
49import * as Effect from "effect/Effect";
50import AuthApi from "./src/worker.ts";
51
52export default Alchemy.Stack(
53 "BetterAuthD1",
54 {
55 providers: Cloudflare.providers(),
56 state: Alchemy.localState(),
57 },
58 Effect.gen(function* () {
59 const api = yield* AuthApi;
60 return { url: api.url.as<string>() };
61 }),
62);
63```
64
65Omitting `secret` provisions and binds a stable signing secret automatically. Preserve and protect the local `.alchemy` state directory across deployments.
66
67## Deploy or develop locally
68
69```sh
70bunx alchemy deploy
71```
72
73Deployment creates D1 and applies the auth schema through its HTTP API before updating the Worker. Requests use the native binding and never run migrations.
74
75```sh
76bunx alchemy dev
77```
78
79Development uses the local D1 simulator, including migrations; use the URL printed by Alchemy. The Worker still runs in workerd, so replacing this layer with Bun's `SQLite` is not supported.
80
81## Verify the endpoint
82
83Set `AUTH_ORIGIN` to the URL printed by Alchemy, then request the session endpoint:
84
85```sh
86curl -i "$AUTH_ORIGIN/api/auth/get-session"
87```
88
89## Transaction and migration limits
90
91D1 has no interactive transactions; plugins requiring them, including SCIM in Better Auth 1.7, need a different database. Automatic migrations are additive, not a data-transfer or destructive schema-migration tool.
92
93For existing applications, preserve the signing secret and review the [1.6 to 1.7 upgrade guide](/better-auth/upgrades/from-1-6-to-1-7). See [configuration](/better-auth/guides/configuration) for production origins, [migrations](/better-auth/guides/migrations) for schema ownership, and the [`CloudflareD1` reference](/providers/betterauth/cloudflared1) for layer options.