CLI tool
zpg6/better-auth-cloudflare avatar
zpg6/better-auth-cloudflare

better-auth-cloudflare: wiring Better Auth to Workers, D1 and R2

Seamlessly integrate better-auth with Cloudflare Workers, D1, Hyperdrive, KV, R2, and geolocation services. CLI for project generation, automated resource provisioning on Cloudflare, and database migrations. Supports Next.js, Hono, and more!

592 stars40 forksTypeScriptMIT

At a glance

What is it?
better-auth-cloudflare is a plugin and CLI that connects the Better Auth library to Cloudflare's platform, covering D1, Postgres and MySQL through Drizzle or native D1, Hyperdrive, KV secondary storage, R2 file storage and geolocation enrichment of sessions. The CLI generates a project from a template and provisions the Cloudflare resources, or you wire it up by hand in about seven steps.
Who is it for?
Adopt better-auth-cloudflare if you are running Better Auth on Cloudflare Workers and want D1, Hyperdrive, KV, R2 and Cloudflare geolocation wired up without hand-writing the adapters and schema each time. Do not adopt it if you are on a different platform, since the package is a Cloudflare integration, and note that the version is pre-1.0 with the roadmap still listing Durable Objects, Cloudflare Email and Images.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 11 days ago.
What is it written in?
Mainly TypeScript, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

A plugin for the platform, not a replacement for the auth library

better-auth-cloudflare integrates Better Auth with Cloudflare Workers, D1, Hyperdrive, KV, R2 and geolocation services. The auth library itself is Better Auth, and this package is the layer that connects it to the Cloudflare platform.

The feature list is what makes that concrete.

Database integration covers D1, which is SQLite, Postgres and MySQL through Drizzle ORM, or native D1 without Drizzle. Hyperdrive support connects to Postgres and MySQL databases through Cloudflare Hyperdrive, which is the pooled connection layer in front of a database that does not run in the Worker. KV storage integration is optional secondary storage, and the readme gives session caching as the example.

R2 file storage covers uploading, downloading and managing user files with Cloudflare R2 object storage and database tracking, so the file metadata lives in your database and the bytes live in R2.

Then the two Cloudflare specific features. Automatic geolocation tracking enriches user sessions with location data derived from Cloudflare, and Cloudflare IP detection uses Cloudflare's IP detection headers out of the box. A client plugin exposes rich context to the client side, including timezone, city, country and region.

The configuration table at the end of the readme is short and tells you the defaults. autoDetectIpAddress is a boolean defaulting to true, geolocationTracking is a boolean defaulting to true, the cf option is an object or function defaulting to undefined and requests geolocation context, with a note to pass a function when one auth instance serves many requests, and r2 is an object for the bucket configuration.

That last note about cf is a real design point rather than a detail. A single Worker handling many tenants cannot have one set of Cloudflare bindings, so the option accepts a function, which is how you resolve the right context per request.

The CLI generates a project and provisions the resources

The command line tool is the fast path, and it does more than write files.

In interactive mode it asks questions and provides helpful defaults:

bash
npx @better-auth-cloudflare/cli@latest generate

And the non-interactive mode takes arguments, in this case generating a simple D1 app with KV and deploying it fully to Cloudflare:

bash
# Simple D1 app with KV (fully deployed to Cloudflare)
npx @better-auth-cloudflare/cli@latest generate \
  --app-name=my-auth-app \
  --template=hono \
  --database=d1 \
  --kv=true \
  --r2=false \
  --apply-migrations=prod

The migration workflow has the same two forms:

bash
npx @better-auth-cloudflare/cli@latest migrate                         # Interactive
npx @better-auth-cloudflare/cli@latest migrate --migrate-target=prod   # Non-interactive

The CLI creates projects from Hono or Next.js templates and can automatically set up D1, KV, R2 and Hyperdrive resources, with the full documentation in the cli directory.

The command list in the roadmap shows where the tool is. generate, migrate, version and help are done. The integrate command, which would add better-auth-cloudflare to an existing project and create or update the auth and schema files, is not done, and neither is the plugin command, which would generate an empty Better Auth plugin for adding typesafe endpoints and schema fields. That is a meaningful gap for anyone with an existing project, because it means the automated path currently only works for new projects generated from a template.

There is a troubleshooting note worth knowing. If the CLI fails with an ERR_REQUIRE_ESM error, the node version needs to be at least v23.0.0, v22.12.0 or v20.19.0 depending on the major version you use.

The library itself installs the usual way, and the readme lists four package managers:

bash
npm install better-auth-cloudflare
# or
yarn add better-auth-cloudflare
# or
pnpm add better-auth-cloudflare
# or
bun add better-auth-cloudflare

Manual setup is seven steps, and the schema merge is the first one

If you are not generating a project from scratch, the readme documents a manual setup as a numbered list.

Step one is defining your database schema in src/db/schema.ts, and the instruction is that you need to merge the Better Auth schema with any other Drizzle schemas your application uses, so that Drizzle can manage the entire database structure including the tables Better Auth requires. That merge is the step people get wrong, because the auth tables have to live in the same Drizzle schema as everything else for the migrations to be coherent.

Step two initialises Drizzle ORM in src/db/index.ts, step three configures Better Auth in src/auth/index.ts, and step four generates and manages the auth schema, which is the step that produces the table definitions the migrations are built from.

Step five configures KV as secondary storage, and it is optional. The readme attaches a warning to it: KV and session revocation. The reason is structural. KV is a key value store with eventual consistency, and a session cached there is not something you can delete synchronously, so revoking a session is not immediate. That is a property of the datastore rather than of this plugin, and it is the kind of thing that has to be designed around rather than discovered.

Steps six and seven set up the API routes and initialise the client, and there is a separate guide for R2 file storage at docs/r2.md and a configuration reference at docs/configuration.md.

The live demos are the fastest way to see the shape of the result. One runs on OpenNextJS, which is the Cloudflare adapter for Next.js, and one runs on Hono, and both are deployed on Workers under the author's workers.dev subdomain, with the source of both in the examples directory.

Geolocation as a session field, and the client plugin

The two Cloudflare specific features deserve a closer look, because they are the ones a project on another platform cannot easily reproduce.

Geolocation tracking writes location data into the session, derived from what Cloudflare already knows about the connection. The point of putting it in the session rather than looking it up per request is that Cloudflare has already done the lookup. A Worker behind Cloudflare's network receives the request with the client's country and city attached, and the plugin's job is to copy that into the session record the auth library already maintains.

That turns location into something an application can reason about later, such as a default currency or a regional default, without a separate geolocation call and without the client telling you where it is. The IP detection piece is the same idea one level down, using Cloudflare's IP detection headers out of the box, and it is what makes the geolocation work at all, since Cloudflare needs to know the client address to say where the client is.

The client plugin is the last piece and it is the one that would be easiest to get wrong. Rich client-side context means the timezone, city, country, region and more are available in the browser, which sounds like a small thing and is not. Timezone in particular is the one that matters for any app that shows times: a server-side timestamp in UTC rendered in a client-side locale is only correct if the client knows its own timezone, and the browser knows it, while the server has to guess or ask.

Both features are opt-out rather than opt-in, with autoDetectIpAddress and geolocationTracking both defaulting to true. That is a reasonable default for a Cloudflare plugin, and it is worth being deliberate about it if your privacy obligations are stricter than the defaults, because the session table will start accumulating location data as soon as you install the package.

The cf configuration option, which can be an object or a function, is the escape hatch for the multi-tenant case, where one Worker serves many customers and the Cloudflare context has to be resolved per request rather than once at startup.

Versions, dependencies and the shape of the package

The package is small and the dependency list tells you what it is.

The runtime dependencies are two, drizzle-orm at 0.45.0 or newer and zod at 4.3.0 or newer, and the peer dependencies are @better-auth/drizzle-adapter at 1.5.0 or newer and better-auth itself at 1.5.0 or newer. So the auth library and its Drizzle adapter are peers, which is the right arrangement: you control which version of Better Auth you use, and this package only needs to be compatible with a range.

The build is unbuild, producing a CJS entry at dist/index.cjs, an ESM entry at dist/index.mjs and types at dist/index.d.ts, and the package is marked as an ES module with the type set to module. The published files are only the dist directory.

The test setup has two layers, jest for the main test script and a separate unit test script using the Node test runner, and there is a Playwright config and an e2e directory for browser tests, plus husky for the commit hooks and prettier for formatting. The dev dependencies also include @cloudflare/workers-types, which is how the Cloudflare runtime types are brought in for the typecheck, and pkg-pr-new, which is the tool that publishes a preview of a pull request to npm so a reviewer can install the branch.

The version is 0.4.1, published on 2026-10-12, with 0.4.0 the same day and 0.3.1 in July 2026. The homepage is better-auth-cloudflare.com, the licence is MIT, and the author is Zach Grimaldi.

The roadmap is the part to check before you commit, and it is a mixed list. IP detection, geolocation, D1, Hyperdrive, KV and R2 are all done. Cloudflare Email, Cloudflare Images, Durable Objects and D1 multi-tenancy are not. On the examples side, Hono and OpenNextJS are done, and SvelteKit with Hyperdrive and TanStack Start with Durable Objects are not, which lines up with the two unfinished platform features they would need.

Editorial conclusion

Adopt better-auth-cloudflare if you are running Better Auth on Cloudflare Workers and want D1, Hyperdrive, KV, R2 and Cloudflare geolocation wired up without hand-writing the adapters and schema each time. Do not adopt it if you are on a different platform, since the package is a Cloudflare integration, and note that the version is pre-1.0 with the roadmap still listing Durable Objects, Cloudflare Email and Images. Before you commit, read the configuration reference for the cf option, and decide between the CLI route and the manual setup, because the CLI provisions real Cloudflare resources and applies migrations to production.

Frequently asked questions

What does better-auth-cloudflare do?

It integrates the Better Auth library with Cloudflare Workers, D1, Hyperdrive, KV, R2 and geolocation services. It supports D1, Postgres and MySQL through Drizzle ORM or native D1, optional KV secondary storage, R2 file storage with database tracking, and automatic geolocation and IP detection from Cloudflare.

How do I generate a project with the better-auth-cloudflare CLI?

Run npx @better-auth-cloudflare/cli@latest generate, which asks questions interactively, or pass arguments for a non-interactive run such as --app-name, --template, --database, --kv, --r2 and --apply-migrations. The CLI creates projects from Hono or Next.js templates and can set up D1, KV, R2 and Hyperdrive resources on Cloudflare.

What are the configuration options for better-auth-cloudflare?

autoDetectIpAddress is a boolean defaulting to true, geolocationTracking is a boolean defaulting to true, cf is an object or function defaulting to undefined for requesting geolocation context, where a function is used when one auth instance serves many requests, and r2 is an object for the bucket configuration. The full WithCloudflareOptions interface is in the configuration reference.

Is there a caveat about using KV for session storage?

Yes. The readme flags KV and session revocation in the optional secondary storage step, because a session cached in KV cannot be deleted synchronously, so revocation is not immediate. The database and the KV secondary storage are separate steps in the manual setup, and only the secondary storage is optional.

What is not finished in better-auth-cloudflare yet?

On the platform side, Cloudflare Email, Cloudflare Images, Durable Objects and D1 multi-tenancy are still unchecked on the roadmap. On the CLI side, the integrate command for adding the package to an existing project and the plugin command for generating a Better Auth plugin are not done, and the SvelteKit and TanStack Start examples are pending.

Official sources

  1. License: MIT
  2. Project website
  3. README
  4. Releases
  5. zpg6/better-auth-cloudflare on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/zpg6-better-auth-cloudflare.svg)](https://hysenlabs.com/projects/zpg6-better-auth-cloudflare)

Was this useful?