Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 13 additions & 0 deletions examples/tanstack-start/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
node_modules
.DS_Store
dist
dist-ssr
*.local
.env
.nitro
.tanstack
.wrangler
.output
.vinxi
__unconfig*
todos.json
151 changes: 151 additions & 0 deletions examples/tanstack-start/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
This is an example TanStack Start application using [better-auth-cloudflare](https://github.com/better-auth/better-auth).

See a live demo at [https://better-auth-cloudflare-tanstack-template.ahut10.workers.dev](https://better-auth-cloudflare-tanstack-template.ahut10.workers.dev).

> ⚠️ intension is The demo database will be wiped on a schedule to keep it from filling up — don't rely on any data you create there persisting.

> 🐛 Known issue: the Cloudflare-aware `request.cf` properties don't appear to be populating in the deployed demo right now. If you know why (or have ideas on how to debug it), contributions / pointers would be very welcome.

# Getting Started

Install dependencies:

```bash
pnpm install
```

Then follow the setup steps below to configure Cloudflare and Better Auth before running the dev server.

## Setting up Cloudflare (Wrangler)

This app runs on Cloudflare Workers and uses a D1 database and a KV namespace. The repo does **not** ship a `wrangler.jsonc` — you need to create one and provision the resources yourself. The code expects the bindings to be named **`db`** (D1) and **`kv`** (KV).

1. Install Wrangler and log in:

```bash
pnpm add -D wrangler
pnpm wrangler login
```

2. Create the D1 database:

```bash
pnpm wrangler d1 create db
```

Copy the `database_id` from the command's output.

> 💡 If you only intend to develop locally, you can skip the `--remote` flag (which is the default behaviour here) — Wrangler will provision a local SQLite file under `.wrangler/` on the first `pnpm dev` run, and you won't consume any of your Cloudflare D1 quota.

3. Create the KV namespace:

```bash
pnpm wrangler kv namespace create kv
```

Copy the `id` from the output.

4. The Wrangler commands above will create/update `wrangler.jsonc` for you and print the binding snippets to paste. Ensure your `wrangler.jsonc` ends up looking approximately like this (with the IDs from the previous steps filled in):

```jsonc
{
"$schema": "node_modules/wrangler/config-schema.json",
"name": "tanstack-start-app",
"compatibility_date": "2025-09-02",
"compatibility_flags": ["nodejs_compat"],
"main": "src/server.ts",
"d1_databases": [
{
"binding": "db",
"database_name": "db",
"database_id": "<your-d1-database-id>"
}
],
"kv_namespaces": [
{
"binding": "kv",
"id": "<your-kv-namespace-id>"
}
]
}
```

> ⚠️ The `binding` values **must** be `db` and `kv` — the auth setup in `src/lib/auth.ts` reads them by those names. In addition, the D1 `database_name` **must** also be `db`, because the `generate:db`, `migrate:dev`, and `migrate:prod` scripts in `package.json` reference the database by that name (`wrangler d1 migrations apply db ...`). If you want to use a different name, update those scripts to match.

5. Generate the Better Auth schema. The repo ships **without** `src/db/auth.schema.ts` and **without** any migrations — you generate them yourself:

```bash
pnpm generate:auth
```

This creates `src/db/auth.schema.ts` from `src/lib/auth.ts`.

6. Generate Cloudflare binding types (needed so TypeScript knows about `db` and `kv`):

```bash
pnpm generate:cf-types
```

7. Generate the initial Drizzle migration SQL from the schema:

```bash
pnpm generate:db
```

This writes a new migration file under `drizzle/`.

8. Apply the migration to your local D1 database:

```bash
pnpm migrate:dev
```

## Setting up Better Auth

1. Generate and set the `BETTER_AUTH_SECRET` environment variable in your `.env.local`:

```bash
pnpm dlx @better-auth/cli secret
```

2. Also set `BETTER_AUTH_URL=http://localhost:3000` in `.env.local`.

3. Visit the [Better Auth documentation](https://www.better-auth.com) to unlock the full potential of authentication in your app.

## Running the dev server

Once the steps above are complete:

```bash
pnpm dev
```

The app will be available at [http://localhost:3000](http://localhost:3000).

---

# Building & Deploying to Production

Build the app:

```bash
pnpm build
```

Apply migrations to your remote Cloudflare D1 database:

```bash
pnpm migrate:prod
```

Push your `BETTER_AUTH_SECRET` as a Cloudflare secret:

```bash
pnpm wrangler secret put BETTER_AUTH_SECRET
```

Deploy:

```bash
pnpm deploy
```
42 changes: 42 additions & 0 deletions examples/tanstack-start/drizzle.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
import { defineConfig } from "drizzle-kit";
import fs from "node:fs";
import path from "node:path";

function getLocalD1DB() {
try {
const basePath = path.resolve(".wrangler");
const dbFile = fs
.readdirSync(basePath, { encoding: "utf-8", recursive: true })
.find(f => f.endsWith(".sqlite"));

if (!dbFile) {
throw new Error(`.sqlite file not found in ${basePath}`);
}

const url = path.resolve(basePath, dbFile);
return url;
} catch (err) {
console.log(`Error ${err}`);
}
}

export default defineConfig({
dialect: "sqlite",
schema: "./src/db/schema.ts",
out: "./migrations",
...(process.env.NODE_ENV === "production"
? {
driver: "d1-http",
dbCredentials: {
accountId: process.env.CLOUDFLARE_D1_ACCOUNT_ID,
databaseId: process.env.CLOUDFLARE_DATABASE_ID,
token: process.env.CLOUDFLARE_D1_API_TOKEN,
},
}
: {
dbCredentials: {
url: getLocalD1DB(),
},
}),
});

55 changes: 55 additions & 0 deletions examples/tanstack-start/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
{
"name": "test-better-cloudflare",
"private": true,
"type": "module",
"imports": {
"#/*": "./src/*"
},
"scripts": {
"generate:auth": "npx @better-auth/cli@latest generate --config src/lib/auth.ts --output src/db/auth.schema.ts -y",
"dev": "vite dev --port 3000",
"build": "vite build",
"preview": "vite preview",
"test": "vitest run",
"generate:cf-types": "wrangler types src/cf-types.d.ts",
"generate:db": "drizzle-kit generate",
"migrate:dev": "wrangler d1 migrations apply db --local",
"migrate:prod": "wrangler d1 migrations apply db --remote",
"studio:dev": "drizzle-kit studio",
"studio:prod": "NODE_ENV=production drizzle-kit studio"
},
"dependencies": {
"@cloudflare/vite-plugin": "^1.26.0",
"@libsql/client": "^0.17.2",
"@tailwindcss/vite": "^4.1.18",
"@tanstack/react-devtools": "latest",
"@tanstack/react-router": "latest",
"@tanstack/react-router-devtools": "latest",
"@tanstack/react-router-ssr-query": "latest",
"@tanstack/react-start": "latest",
"@tanstack/router-plugin": "^1.132.0",
"better-auth": "^1.6.5",
"better-auth-cloudflare": "file:../../",
"drizzle-orm": "^0.45.2",
"lucide-react": "^0.545.0",
"react": "^19.2.0",
"react-dom": "^19.2.0",
"tailwindcss": "^4.1.18"
},
"devDependencies": {
"@tailwindcss/typography": "^0.5.16",
"@tanstack/devtools-vite": "latest",
"@testing-library/dom": "^10.4.1",
"@testing-library/react": "^16.3.0",
"@types/node": "^22.10.2",
"@types/react": "^19.2.0",
"@types/react-dom": "^19.2.0",
"@vitejs/plugin-react": "^6.0.1",
"drizzle-kit": "^0.31.10",
"jsdom": "^28.1.0",
"typescript": "^5.7.2",
"vite": "^8.0.0",
"vitest": "^3.0.5",
"wrangler": "^4.70.0"
}
}
Binary file added examples/tanstack-start/public/favicon.ico
Binary file not shown.
Binary file added examples/tanstack-start/public/logo192.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added examples/tanstack-start/public/logo512.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
25 changes: 25 additions & 0 deletions examples/tanstack-start/public/manifest.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
{
"short_name": "TanStack App",
"name": "Create TanStack App Sample",
"icons": [
{
"src": "favicon.ico",
"sizes": "64x64 32x32 24x24 16x16",
"type": "image/x-icon"
},
{
"src": "logo192.png",
"type": "image/png",
"sizes": "192x192"
},
{
"src": "logo512.png",
"type": "image/png",
"sizes": "512x512"
}
],
"start_url": ".",
"display": "standalone",
"theme_color": "#000000",
"background_color": "#ffffff"
}
3 changes: 3 additions & 0 deletions examples/tanstack-start/public/robots.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# https://www.robotstxt.org/robotstxt.html
User-agent: *
Disallow:
Loading