Back to Skills

Better Auth

Skill for integrating Better Auth - comprehensive TypeScript authentication framework for Cloudflare D1, Next.js, Nuxt, and 15+ frameworks. Use when adding auth, encountering D1 adapter errors, or implementing OAuth/2FA/RBAC features.

typescriptcloudflare

Skill Content

# better-auth

**Status**: Production Ready
**Last Updated**: 2026-04-08
**Package**: `better-auth@1.6.0` (ESM-only)
**Dependencies**: Drizzle ORM or Kysely (required for D1 complex use cases; D1 native support available in v1.5+)

---

## Quick Start (5 Minutes)

### Installation

**Option 1: Drizzle ORM (Recommended)**
```bash
bun add better-auth drizzle-orm drizzle-kit
```

**Option 2: Kysely**
```bash
bun add better-auth kysely @noxharmonium/kysely-d1
```

### ⚠️ v1.4.0+ Requirements

better-auth v1.4.0+ is **ESM-only**. Ensure:

**package.json**:
```json
{
  "type": "module"
}
```

**Upgrading from v1.3.x?** Load `references/migration-guide-1.4.0.md`
**Upgrading from v1.4.x?** Load `references/migration-guide-1.5.0.md`

### ⚠️ CRITICAL: D1 Adapter Requirements

**v1.5.0+**: D1 is now natively supported. Pass your D1 binding directly:

```typescript
// ✅ SIMPLEST - D1 native (v1.5.0+)
import { betterAuth } from "better-auth";

const auth = betterAuth({
    database: env.DB, // D1 binding, auto-detected
});
```

For complex schemas, use Drizzle ORM:
```typescript
// ✅ RECOMMENDED for complex schemas - Drizzle
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { drizzle } from "drizzle-orm/d1";

const auth = betterAuth({
    database: drizzleAdapter(drizzle(env.DB, { schema }), { provider: "sqlite" }),
});
```

```typescript
// ❌ WRONG - This doesn't exist
import { d1Adapter } from 'better-auth/adapters/d1'
```

### Minimal Setup (Cloudflare Workers + Drizzle)

**1. Create D1 Database:**
```bash
wrangler d1 create my-app-db
```

**2. Define Schema** (`src/db/schema.ts`):
```typescript
import { integer, sqliteTable, text } from "drizzle-orm/sqlite-core";

export const user = sqliteTable("user", {
  id: text().primaryKey(),
  name: text().notNull(),
  email: text().notNull().unique(),
  emailVerified: integer({ mode: "boolean" }).notNull().default(false),
  image: text(),
});

export const session = sqliteTable("session", {
  id: text().primaryKey(),
  userId: text().notNull().references(() => user.id, { onDelete: "cascade" }),
  token: text().notNull(),
  expiresAt: integer({ mode: "timestamp" }).notNull(),
});

// See references/database-schema.ts for complete schema
```

**3. Initialize Auth** (`src/auth.ts`):
```typescript
import { betterAuth } from "better-auth";
import { drizzleAdapter } from "better-auth/adapters/drizzle";
import { drizzle } from "drizzle-orm/d1";
import * as schema from "./db/schema";

export function createAuth(env: { DB: D1Database; BETTER_AUTH_SECRET: string }) {
  const db = drizzle(env.DB, { schema });

  return betterAuth({
    baseURL: env.BETTER_AUTH_URL,
    secret: env.BETTER_AUTH_SECRET,
    database: drizzleAdapter(db, { provider: "sqlite" }),
    emailAndPassword: { enabled: true },
  });
}
```

**4. Create Worker** (`src/index.ts`):
```typescript
import { Hono } from "hono";
import { createAuth } from "./auth";

const app = new Hono<{ Bindings: Env }>();

app.all("/api/auth/*", async (c) => {
  const auth = createAuth(c.env);
  return auth.handler(c.req.raw);
});

export default app;
```

**5. Deploy:**
```bash
bunx drizzle-kit generate
wrangler d1 migrations apply my-app-db --remote
wrangler deploy
```

---

## Decision Tree

**For code examples and syntax, always consult [better-auth.com/docs](https://better-auth.com/docs).**

```
Is this a new/empty project?
├─ YES → New project setup
│   1. Identify framework (Next.js, Nuxt, Workers, etc.)
│   2. Choose database (D1, PostgreSQL, MongoDB, MySQL)
│   3. Install better-auth + Drizzle/Kysely
│   4. Create auth.ts + auth-client.ts
│   5. Set up route handler (see Quick Start above)
│   6. Run migrations (Drizzle Kit for D1)
│   7. Add features via plugins (2FA, organizations, etc.)
│
└─ NO → Does project have existing auth?
    ├─ YES → Migration/enhancement
    │   • Audit current auth for gaps
    │   • Plan incremental migration
    │   • See references/framework-comparison.md for migration guides
    │
    └─ NO → Add auth to existing project
        1. Analyze project structure
        2. Install better-auth + adapter
        3. Create auth config (see Quick Start)
        4. Add route handler to existing routes
        5. Run schema migrations
        6. Integrate into existing pages/components
```

---

## Critical Rules

### MUST DO

✅ Use `better-auth/minimal` + adapter packages for smallest bundle (v1.5+)
✅ Use `npx auth migrate` and `npx auth generate` for CLI commands (v1.5+)
✅ Set BETTER_AUTH_SECRET via `wrangler secret put`
✅ Configure CORS with `credentials: true`
✅ Match OAuth callback URLs exactly (no trailing slash)
✅ Apply migrations to local D1 before `wrangler dev`
✅ Use camelCase column names in schema

### NEVER DO

❌ Use `d1Adapter` (doesn't exist)
❌ Forget CORS credentials or mismatch OAuth URLs
❌ Use snake_case columns without CamelCasePlugin
❌ Skip local migrations or hardcode secrets
❌ Leave sendVerificationEmail unimplemented

### ⚠️ v1.5.0 Breaking Changes

**API Key Plugin Moved**:
```typescript
- import { apiKey } from "better-auth/plugins";
+ import { apiKey } from "@better-auth/api-key";
```
Schema: `userId` → `referenceId`, new `configId` field.

**After Hooks**: Database after-hooks now run post-transaction (not inside it).

**Deprecated APIs Removed**: `Adapter` → `DBAdapter`, `InferUser`/`InferSession` removed, `@better-auth/core/utils` split into subpath exports.

**Load `references/migration-guide-1.5.0.md` when upgrading from <1.5.0**

### ⚠️ v1.6.0 Breaking Changes

**Session Freshness**: `freshAge` now uses `createdAt` (not `updatedAt`). Sessions may require re-auth more frequently for sensitive operations.

**SAML Security**: InResponseTo validation is **default ON**. Opt out with `saml: { enableInResponseToValidation: false }`.

**OIDC Provider Deprecated**: Use `@better-auth/oauth-provider` instead.

### New in v1.5.0 (Highlights)

- **New CLI**: `npx auth init/migrate/generate/upgrade`
- **D1 Native**: Pass D1 binding directly (no adapter needed)
- **OAuth 2.1 Provider**: `@better-auth/oauth-provider` (MCP-ready)
- **Electron**: `@better-auth/electron` for desktop apps
- **i18n**: `@better-auth/i18n` for error translations
- **Dynamic Base URL**: Multi-domain/preview deployment support
- **Secret Key Rotation**: Non-destructive, versioned secrets
- **Test Utils**: Factories, OTP capture, login helpers
- **Typed Error Codes**: Machine-readable `code` in error responses

**Load `references/v1.5-features.md` for detailed implementation guides.**

### New in v1.6.0 (Highlights)

- **OpenTelemetry**: Distributed tracing (experimental)
- **Passkey Pre-Auth**: Register passkeys before session
- **Non-blocking Scrypt**: Password hashing on libuv thread pool
- **46% Smaller Package**: 4.2MB → 2.3MB
- **Case Insensitive Queries**: `mode: "insensitive"` on adapter queries

**Load `references/v1.6-features.md` for detailed implementation guides.**

---

## Quick Reference

### Environment Variables

| Variable | Purpose | Example |
|----------|---------|---------|
| `BETTER_AUTH_SECRET` | Encryption secret (min 32 chars) | Generate: `openssl rand -base64 32` |
| `BETTER_AUTH_URL` | Base URL | `https://example.com` or `http://localhost:8787` |
| `DATABASE_URL` | Database connection (optional for D1) | PostgreSQL/MySQL connection string |

**Note**: Only define `baseURL`/`secret` in config if env vars are NOT set.

### CLI Commands (v1.5+)

| Command | Purpose |
|---------|---------|
| `npx auth init` | Interactive project scaffolding |
| `npx auth migrate` | Run database migrations |
| `npx auth generate` | Generate auth schema |
| `npx auth generate --adapter drizzle` | Adapter-specific schema |
| `npx auth upgrade` | Upgrade to latest version |
| `bunx drizzle-kit generate` | **D1: Use this** to generate Drizzle migrations |
| `wrangler d1 migrations apply DB_NAME` | **D1: Use this** to apply migrations |

**Re-run after adding/changing plugins.**

### Core Config Options

| Option | Notes |
|--------|-------|
| `appName` | Optional display name |
| `baseURL` | Only if `BETTER_AUTH_URL` not set |
| `basePath` | Default `/api/auth`. Set `/` for root. |
| `secret` | Only if `BETTER_AUTH_SECRET` not set (min 32 chars) |
| `database` | **Required** for most features. Use `drizzleAdapter()` or Kysely for D1 |
| `secondaryStorage` | Redis/KV for sessions & rate limits |
| `emailAndPassword` | `{ enabled: true }` to activate |
| `socialProviders` | `{ google: { clientId, clientSecret }, ... }` |
| `plugins` | Array of plugins (import from dedicated paths) |
| `trustedOrigins` | CSRF whitelist for cross-origin requests |

### Common Plugins

Import from **dedicated packages** (extracted in v1.5+):
```typescript
import { twoFactor } from "better-auth/plugins/two-factor"
import { organization } from "better-auth/plugins/organization"
import { passkey } from "@better-auth/passkey"          // Separate package
import { apiKey } from "@better-auth/api-key"            // Separate package (v1.5+)
import { sso } from "@better-auth/sso"                   // Separate package (v1.5+)
import { i18n } from "@better-auth/i18n"                 // Separate package (v1.5+)
import { oauthProvider } from "@better-auth/oauth-provider" // Separate package (v1.5+)
```

Core plugins (still in `better-auth/plugins`): `twoFactor`, `organization`, `admin`, `anonymous`, `emailOTP`, `magicLink`, `phone-number`, `multi-session`, `custom-session`.

---

## Top 5 Errors (See references/error-catalog.md for all 15)

### Error #1: "d1Adapter is not exported"
**Problem**: Trying to use non-existent `d1Adapter`
**Solution**: Use `drizzleAdapter` or Kysely instead (see Quick Start above)

### Error #2: Schema Generation Fails
**Problem**: `better-auth migrate` doesn't work with D1
**Solution**: Use `bunx drizzle-kit generate` then `wrangler d1 migrations apply`

### Error #3: CamelCase vs snake_case Mismatch
**Problem**: Database uses `email_verified` but better-auth expects `emailVerified`
**Solution**: Use camelCase in schema or add `CamelCasePlugin` to Kysely

### Error #4: CORS Errors
**Problem**: `Access-Control-Allow-Origin` errors, cookies not sent
**Solution**: Configure CORS with `credentials: true` and correct origins

### Error #5: OAuth Redirect URI Mismatch
**Problem**: Social sign-in fails with "redirect_uri_mismatch"
**Solution**: Ensure exact match: `https://yourdomain.com/api/auth/callback/google`

**Load `references/error-catalog.md` for all 15 errors with detailed solutions.**

---

## Common Use Cases

### Use Case 1: Email/Password Authentication
**When**: Basic authentication without social providers
**Quick Pattern**:
```typescript
// Client
await authClient.signIn.email({
  email: "user@example.com",
  password: "password123",
});

// Server - enable in config
emailAndPassword: {
  enabled: true,
  requireEmailVerification: true,
}
```
**Load**: `references/setup-guide.md` → Step 5

### Use Case 2: Social Authentication (45+ Providers)
**When**: Allow users to sign in with social accounts
**Supported**: Google, GitHub, Microsoft, Apple, Discord, TikTok, Twitch, Spotify, LinkedIn, Slack, Reddit, Facebook, Twitter/X, Patreon, Vercel, Kick, and 30+ more.
**Quick Pattern**:
```typescript
// Client
await authClient.signIn.social({
  provider: "google",
  callbackURL: "/dashboard",
});

// Server config
socialProviders: {
  google: {
    clientId: env.GOOGLE_CLIENT_ID,
    clientSecret: env.GOOGLE_CLIENT_SECRET,
    scope: ["openid", "email", "profile"],
  },
}
```
**Load**: `references/setup-guide.md` → Step 5

### Use Case 3: Protected API Routes
**When**: Need to verify user is authenticated
**Quick Pattern**:
```typescript
app.get("/api/protected", async (c) => {
  const auth = createAuth(c.env);
  const session = await auth.api.getSession({
    headers: c.req.raw.headers,
  });

  if (!session) {
    return c.json({ error: "Unauthorized" }, 401);
  }

  return c.json({ data: "protected", user: session.user });
});
```
**Load**: `references/cloudflare-worker-drizzle.ts`

### Use Case 4: Multi-Tenant with Organizations
**When**: Building SaaS with teams/organizations
**Load**: `references/advanced-features.md` → Organizations & Teams

### Use Case 5: Two-Factor Authentication
**When**: Need extra security with 2FA/TOTP
**Load**: `references/advanced-features.md` → Two-Factor Authentication

---

## When to Load References

**Load `references/setup-guide.md` when**:
- User needs complete 8-step setup walkthrough
- User asks about Kysely adapter alternative
- User needs help with migrations or deployment
- User asks about wrangler.toml configuration

**Load `references/error-catalog.md` when**:
- Encountering any of the 15 documented errors
- User reports D1 adapter, schema, CORS, or OAuth issues
- User asks about troubleshooting or debugging
- User needs prevention checklist

**Load `references/advanced-features.md` when**:
- User asks about 2FA, passkeys, or magic links
- User needs organizations, teams, or RBAC
- User asks about rate limiting or session management
- User wants migration guide from Clerk or Auth.js
- User needs security best practices or performance optimization

**Load `references/v1.5-features.md` when**:
- User asks about the new CLI, MCP auth, OAuth 2.1 Provider
- User needs Electron desktop auth or i18n error translations
- User asks about dynamic base URL or secret key rotation
- User needs D1 native support (no adapter) or adapter extraction
- User asks about test utils, seat-based billing, or typed error codes
- User needs Cloudflare D1 native support configuration

**Load `references/v1.6-features.md` when**:
- User asks about OpenTelemetry or distributed tracing
- User needs passkey pre-auth registration (before session)
- User asks about case-insensitive database queries
- User encounters session freshness issues after upgrading
- User asks about SAML InResponseTo validation

**Load `references/migration-guide-1.5.0.md` when**:
- User upgrading from better-auth <1.5.0 to 1.5.0+
- User encounters API Key import errors (`userId` → `referenceId`)
- User asks about after hooks running post-transaction
- User encounters `InferUser`/`InferSession` type errors
- User needs to update `@better-auth/core/utils` imports

**Load `references/plugins/sso.md` when**:
- User needs production SSO with OIDC, OAuth2, or SAML 2.0
- User asks about OIDC discovery, SAML SLO, or domain verification
- User needs organization provisioning via SSO
- User asks about SAML security (InResponseTo, replay protection, timestamps)
- User encounters SSO discovery errors

**Load `references/plugins/test-utils.md` when**:
- User writing integration or E2E tests with Better Auth
- User needs test factories (createUser, createOrganization)
- User needs authenticated test sessions (login, getAuthHeaders, getCookies)
- User needs OTP capture for verification tests

**Load `references/integrations/electron.md` when**:
- User building Electron desktop app with Better Auth
- User needs system browser OAuth flow for desktop
- User asks about deep links, custom protocol schemes
- User needs IPC bridges or manual token exchange

**Load `references/cloudflare-worker-drizzle.ts` when**:
- User needs complete Worker implementation example
- User asks for production-ready code
- User wants to see full auth flow with protected routes

**Load `references/cloudflare-worker-kysely.ts` when**:
- User prefers Kysely over Drizzle
- User asks for Kysely-specific implementation

**Load `references/database-schema.ts` when**:
- User needs complete better-auth schema with all tables
- User asks about custom tables or schema extension
- User needs TypeScript types for database

**Load `references/react-client-hooks.tsx` when**:
- User building React/Next.js frontend
- User needs login forms, session hooks, or protected routes
- User asks about client-side implementation

**Load `references/configuration-guide.md` when**:
- User asks about production configuration
- User needs environment variable setup or wrangler.toml
- User asks about dynamic base URL, secret rotation, or D1 native
- User needs CORS configuration, rate limiting, or API keys
- User asks about session configuration (deferSessionRefresh, verification on secondary storage)

**Load `references/framework-comparison.md` when**:
- User asks "better-auth vs Clerk" or "vs Auth.js"
- User needs help choosing auth framework
- User wants feature comparison, migration advice, or cost analysis

**Load `references/migration-guide-1.4.0.md` when**:
- User upgrading from better-auth <1.4.0 to 1.4.0+
- User encounters `forgetPassword` errors or ESM issues
- User asks about breaking changes or migration steps

**Load `references/v1.4-features.md` when**:
- User asks about background tasks or deferred email sending
- User needs Patreon, Vercel, or Kick OAuth provider setup
- User asks about the better-auth CLI tool
- User needs admin role permissions configuration

**Load `references/nextjs/README.md` when**:
- User building Next.js app with PostgreSQL (not Cloudflare D1)
- User needs organizations and 2FA example
- User asks about Next.js-specific implementation

**Load `references/nextjs/postgres-example.ts` when**:
- User needs complete Next.js API route implementation
- User wants to see organizations + 2FA in practice
- User asks for PostgreSQL setup with Drizzle

### Framework-Specific Setup

**Load `references/frameworks/nextjs.md` when**:
- User building with Next.js (App Router or Pages Router)
- User needs middleware, Server Components, or API routes

**Load `references/frameworks/nuxt.md` when**:
- User building with Nuxt 3
- User needs H3 handlers, composables, or server routes

**Load `references/frameworks/remix.md` when**:
- User building with Remix
- User needs loader/action patterns or session handling

**Load `references/frameworks/sveltekit.md` when**:
- User building with SvelteKit
- User needs hooks, load functions, or stores

**Load `references/frameworks/api-frameworks.md` when**:
- User building with Express, Fastify, NestJS, or Hono (non-Cloudflare)
- User needs middleware or route configuration

**Load `references/frameworks/expo-mobile.md` when**:
- User building React Native or Expo app
- User needs SecureStore, deep linking, or mobile auth

### Database Adapters

**Load `references/databases/postgresql.md` when**:
- User using PostgreSQL with Drizzle or Prisma
- User needs Neon, Supabase, or connection pooling setup

**Load `references/databases/mongodb.md` when**:
- User using MongoDB
- User needs Atlas setup or indexes

**Load `references/databases/mysql.md` when**:
- User using MySQL or PlanetScale
- User needs Vitess compatibility guidance

### Plugin Guides

**Load `references/plugins/authentication.md` when**:
- User needs 2FA, passkeys (incl. pre-auth), magic links, email OTP, or anonymous users
- User asks about enhanced authentication methods

**Load `references/plugins/enterprise.md` when**:
- User needs organizations, SSO/SAML, SCIM, or admin dashboard
- User building multi-tenant or enterprise application

**Load `references/plugins/api-tokens.md` when**:
- User needs API keys (incl. org-owned, multi-config), bearer tokens, JWT
- User building API authentication for third parties

**Load `references/plugins/payments.md` when**:
- User needs Stripe (incl. seat-based billing) or Polar integration
- User building subscription or payment features

**Load `references/plugins/sso.md` when**:
- User needs production SSO with OIDC, OAuth2, or SAML 2.0
- User asks about OIDC discovery, SAML SLO, domain verification
- User needs organization provisioning via SSO

**Load `references/plugins/test-utils.md` when**:
- User writing integration or E2E tests
- User needs test factories, OTP capture, or authenticated sessions

### Integration Guides

**Load `references/integrations/electron.md` when**:
- User building Electron desktop app with Better Auth
- User needs system browser OAuth, deep links, IPC bridges

---

## Configuration Reference

**Quick Config** (ESM-only in v1.4.0+):
```typescript
export const auth = betterAuth({
  baseURL: env.BETTER_AUTH_URL,
  secret: env.BETTER_AUTH_SECRET,
  database: drizzleAdapter(db, { provider: "sqlite" }),
});
```

**Load `references/configuration-guide.md` for**:
- Production configuration with email/password and social providers
- wrangler.toml setup and environment variables
- Session configuration, CORS setup, and ESM requirements
- Rate limiting, API keys (v1.4.0+), and troubleshooting

---

## Using Bundled Resources

### References (references/)

- **setup-guide.md** - Complete 8-step setup (D1 → Drizzle → Deploy)
- **error-catalog.md** - All 15 errors with solutions and prevention checklist
- **advanced-features.md** - 2FA, organizations, rate limiting, passkeys, magic links, migrations
- **configuration-guide.md** - Production config, dynamic base URL, secret rotation, D1 native
- **framework-comparison.md** - better-auth vs Clerk vs Auth.js, migration paths, TCO
- **migration-guide-1.4.0.md** - Upgrading from v1.3.x to v1.4.0+ (ESM, API changes)
- **migration-guide-1.5.0.md** - Upgrading from v1.4.x to v1.5.0+ (API Key, adapter imports, hooks)
- **v1.4-features.md** - Background tasks, new OAuth providers, SAML/SSO, CLI
- **v1.5-features.md** - New CLI, OAuth 2.1 Provider, Electron, i18n, D1 native, secret rotation
- **v1.6-features.md** - OpenTelemetry, passkey pre-auth, non-blocking scrypt
- **cloudflare-worker-drizzle.ts** - Complete Worker with Drizzle auth
- **cloudflare-worker-kysely.ts** - Complete Worker with Kysely auth
- **database-schema.ts** - Complete better-auth Drizzle schema
- **react-client-hooks.tsx** - React components with auth hooks

### Framework References (references/frameworks/)
- **nextjs.md** - Next.js App/Pages Router integration
- **nuxt.md** - Nuxt 3 with H3 and composables
- **remix.md** - Remix loaders, actions, sessions
- **sveltekit.md** - SvelteKit hooks and stores
- **api-frameworks.md** - Express, Fastify, NestJS, Hono
- **expo-mobile.md** - React Native and Expo

### Database References (references/databases/)
- **postgresql.md** - PostgreSQL with Drizzle/Prisma, Neon/Supabase
- **mongodb.md** - MongoDB adapter and Atlas
- **mysql.md** - MySQL and PlanetScale

### Plugin References (references/plugins/)
- **authentication.md** - 2FA, passkeys (incl. pre-auth), magic links, email OTP, anonymous
- **enterprise.md** - Organizations, SSO, SCIM, admin
- **api-tokens.md** - API keys (incl. org-owned, multi-config), bearer tokens, JWT
- **payments.md** - Stripe, Polar integrations
- **sso.md** - Production SSO: OIDC discovery, SAML SLO, domain verification, security
- **test-utils.md** - Testing helpers: factories, OTP capture, login, Vitest/Playwright

### Integration References (references/integrations/)
- **electron.md** - Electron desktop auth: system browser OAuth, IPC bridges, deep links

### Next.js Examples (references/nextjs/)
- **README.md** - Next.js + PostgreSQL setup guide (not D1)
- **postgres-example.ts** - Complete API route with organizations, 2FA, email verification

### Client Integration

**Create auth client** (`src/lib/auth-client.ts`):
```typescript
import { createAuthClient } from "better-auth/client";

export const authClient = createAuthClient({
  baseURL: import.meta.env.VITE_API_URL || "http://localhost:8787",
});
```

**Use in React**:
```typescript
import { authClient } from "@/lib/auth-client";

export function UserProfile() {
  const { data: session, isPending } = authClient.useSession();

  if (isPending) return <div>Loading...</div>;
  if (!session) return <div>Not authenticated</div>;

  return (
    <div>
      <p>Welcome, {session.user.email}</p>
      <button onClick={() => authClient.signOut()}>Sign Out</button>
    </div>
  );
}
```

---

## Dependencies

**Required**:
- `better-auth@^1.6.0` - Core authentication framework (ESM-only)

**Choose ONE adapter** (optional with D1 native in v1.5+):
- `drizzle-orm@^0.44.7` + `drizzle-kit@^0.31.7` (recommended for complex schemas)
- `kysely@^0.28.8` + `@noxharmonium/kysely-d1@^0.4.0` (alternative)
- `@better-auth/drizzle-adapter` + `better-auth/minimal` (smallest bundle, v1.5+)

**Optional**:
- `@cloudflare/workers-types` - TypeScript types for Workers
- `hono@^4.0.0` - Web framework for routing
- `@better-auth/passkey` - Passkey/WebAuthn plugin
- `@better-auth/api-key` - API key auth with org support
- `@better-auth/sso` - SSO/SAML/OIDC production plugin
- `@better-auth/electron` - Electron desktop auth
- `@better-auth/i18n` - Error message translations
- `@better-auth/oauth-provider` - OAuth 2.1 authorization server

---

## Beyond Cloudflare D1

This skill focuses on **Cloudflare Workers + D1**. better-auth also supports:

**Frameworks** (18 total): Next.js, Nuxt, Remix, SvelteKit, Astro, Express, NestJS, Fastify, Elysia, Expo, and more.

**Databases** (9 adapters): PostgreSQL, MongoDB, MySQL, Prisma, MS SQL, and others.

**Additional Plugins**: Anonymous auth, Email OTP, JWT, Multi-Session, OAuth 2.1 Provider, Test Utils, SCIM, payment integrations (Stripe, Polar), Device Authorization.

**For non-Cloudflare setups**, load the appropriate framework or database reference file, or consult the official docs: https://better-auth.com/docs

---

## Official Documentation

- **better-auth Docs**: https://better-auth.com
- **GitHub**: https://github.com/better-auth/better-auth (22.4k ⭐)
- **Examples**: https://github.com/better-auth/better-auth/tree/main/examples
- **Drizzle Docs**: https://orm.drizzle.team/docs/get-started-sqlite
- **Kysely Docs**: https://kysely.dev/
- **Discord**: https://discord.gg/better-auth

---

## Framework Comparison

**Load `references/framework-comparison.md` for**:
- Complete feature comparison: better-auth vs Clerk vs Auth.js
- v1.4.0+ new features (database joins, stateless sessions, API keys)
- Migration paths, cost analysis, and performance benchmarks
- Recommendations by use case and 5-year TCO

---

## Production Examples

**Verified working repositories** (all use Drizzle or Kysely):

1. **zwily/example-react-router-cloudflare-d1-drizzle-better-auth** - Drizzle
2. **matthewlynch/better-auth-react-router-cloudflare-d1** - Kysely
3. **foxlau/react-router-v7-better-auth** - Drizzle
4. **zpg6/better-auth-cloudflare** - Drizzle (includes CLI)

**Note**: Check each repo's better-auth version. Repos on v1.3.x need v1.4.0+ migration (see `references/migration-guide-1.4.0.md`). None use a direct `d1Adapter` - all require Drizzle/Kysely.

---

## Complete Setup Checklist

- [ ] Verified ESM support (`"type": "module"` in package.json) - v1.4.0+ required
- [ ] Installed better-auth@1.6.0+ (D1 native) or + Drizzle/Kysely
- [ ] Created D1 database with wrangler
- [ ] Defined database schema (or using D1 native without schema)
- [ ] Generated and applied migrations to D1
- [ ] Set BETTER_AUTH_SECRET environment variable
- [ ] Configured baseURL in auth config (or dynamic base URL for previews)
- [ ] Enabled authentication methods (emailAndPassword, socialProviders)
- [ ] Configured CORS with credentials: true
- [ ] Set OAuth callback URLs in provider settings
- [ ] Tested auth routes (/api/auth/*)
- [ ] Tested sign-in, sign-up, session verification
- [ ] Using requestPasswordReset (not forgetPassword) - v1.4.0+ API
- [ ] Using `npx auth` CLI (not `@better-auth/cli`) - v1.5.0+
- [ ] Using `@better-auth/api-key` (not `better-auth/plugins`) for API keys - v1.5.0+
- [ ] Deployed to Cloudflare Workers

---

**Questions? Issues?**

1. Check `references/error-catalog.md` for all 15 errors and solutions
2. Review `references/setup-guide.md` for complete 8-step setup
3. See `references/advanced-features.md` for 2FA, organizations, and more
4. Check official docs: https://better-auth.com
5. Ensure you're using **Drizzle or Kysely** (not non-existent d1Adapter)

How to use

  1. Copy the skill content above
  2. Create a .claude/skills directory in your project
  3. Save as .claude/skills/claude-skills-better-auth.md
  4. Use /claude-skills-better-auth in Claude Code to invoke this skill
View source on GitHub