Firestore better auth
Skill yultyyev/better-auth-firestore/skills/firestore-better-auth
Firestore adapter for Better Auth
npx -y skills add yultyyev/better-auth-firestore --skill firestore-better-authAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
One thing to look at
- 9 stars9 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Use Firestore as the database adapter for Better Auth (Firebase Admin SDK). Use when storing Better Auth users, sessions, accounts, and verification tokens in Firestore, migrating from Auth.js/NextAuth Firebase adapter to Better Auth, setting up Better Auth with a Firebase/Firestore backend, or troubleshooting Firestore index errors and FIREBASE_PRIVATE_KEY issues.
SKILL.md
7.2 KB, as published. Nobody here has run it
Firestore Adapter for Better Auth
better-auth-firestore is the Firestore database adapter for Better Auth. It stores users, sessions, accounts, and verification tokens in Firestore using the Firebase Admin SDK.
Package: better-auth-firestore — GitHub · npm
Install
pnpm add better-auth-firestore firebase-admin better-auth
Minimal setup
import { firestoreAdapter } from "better-auth-firestore";
import { betterAuth } from "better-auth";
import { getFirestore } from "firebase-admin/firestore";
export const auth = betterAuth({
database: firestoreAdapter({ firestore: getFirestore() }),
});
Full setup with credentials
import { betterAuth } from "better-auth";
import { firestoreAdapter, initFirestore } from "better-auth-firestore";
import { cert } from "firebase-admin/app";
const firestore = initFirestore({
credential: cert({
projectId: process.env.FIREBASE_PROJECT_ID!,
clientEmail: process.env.FIREBASE_CLIENT_EMAIL!,
privateKey: process.env.FIREBASE_PRIVATE_KEY!.replace(/\\n/g, "\n"),
}),
projectId: process.env.FIREBASE_PROJECT_ID!,
name: "better-auth",
});
export const auth = betterAuth({
database: firestoreAdapter({
firestore,
namingStrategy: "default", // or "snake_case"
collections: {
// users: "users",
// sessions: "sessions",
// accounts: "accounts",
// verificationTokens: "verificationTokens",
},
}),
});
Options
| Option | Type | Default | Description |
|---|---|---|---|
firestore | Firestore | getFirestore() | Firebase Admin Firestore instance |
namingStrategy | "default" | "snake_case" | "default" | Collection naming convention |
collections | object | see below | Override individual collection names |
debugLogs | boolean | false | Enable verbose query logging |
Default collection names:
users→"users"sessions→"sessions"accounts→"accounts"verificationTokens→"verificationTokens"(default) or"verification_tokens"(snake_case)
Firestore composite index — not required (v1.1+)
No composite index is required. The adapter never combines a where filter with a Firestore orderBy: it applies the filter server-side and sorts the results in memory. Verification-token lookups (identifier == ordered by createdAt desc) work with Firestore's automatic single-field indexes alone.
If sign-in fails with 9 FAILED_PRECONDITION: The query requires an index (Better Auth may surface this as Failed to parse state), you are on an older version. Upgrade to v1.1 or later — do not create the index. Any composite index created for a previous version can be removed afterward.
Optional tooling (only for advanced setups that query the verification collection directly, outside the adapter): generateIndexSetupUrl(projectId, databaseId?, collectionName?) and getIndexConfig(collectionName?), plus the bundled firestore.indexes.json. These default to the verificationTokens collection (use verification_tokens for the snake_case strategy).
Environment variables
FIREBASE_PROJECT_ID=your-project-id
FIREBASE_CLIENT_EMAIL=firebase-adminsdk@your-project.iam.gserviceaccount.com
FIREBASE_PRIVATE_KEY="-----BEGIN PRIVATE KEY-----\n...\n-----END PRIVATE KEY-----\n"
Important: FIREBASE_PRIVATE_KEY often arrives with literal \n strings in env vars. Always replace them:
privateKey: process.env.FIREBASE_PRIVATE_KEY!.replace(/\\n/g, "\n")
Migration from Auth.js / NextAuth Firebase adapter
better-auth-firestore uses the same collection names and field shapes as the Auth.js Firebase adapter by default — it is a drop-in replacement.
// Before (Auth.js)
import { FirestoreAdapter } from "@auth/firebase-adapter";
// After (Better Auth)
import { firestoreAdapter } from "better-auth-firestore";
export const auth = betterAuth({
database: firestoreAdapter({ firestore }),
});
No Firestore data migration needed. Same users, sessions, accounts, and verificationTokens collections.
Using with the Firebase Auth plugin
To also use Firebase Authentication (Phone OTP, Google Sign-In, Email/Password), combine with better-auth-firebase-auth:
import { firestoreAdapter } from "better-auth-firestore";
import { firebaseAuthPlugin } from "better-auth-firebase-auth/server";
export const auth = betterAuth({
database: firestoreAdapter({ firestore }),
plugins: [firebaseAuthPlugin({ firebaseAdminAuth: getAuth() })],
});
Firestore Emulator (local development & tests)
# Start emulator
docker run -d --rm -p 8080:8080 google/cloud-sdk:emulators \
gcloud beta emulators firestore start --host-port=0.0.0.0:8080
# Set env and start dev server
FIRESTORE_EMULATOR_HOST=localhost:8080 pnpm dev
# Run tests
FIRESTORE_EMULATOR_HOST=localhost:8080 pnpm vitest run
No credentials or service account needed when using the emulator.
Runtime support
| Runtime | Supported |
|---|---|
| Node 18+ | ✅ |
| Next.js on Vercel (Node.js runtime) | ✅ Recommended |
| Cloud Functions / Cloud Run | ✅ |
Vercel Edge Runtime (runtime = 'edge') | ❌ Admin SDK requires Node.js |
| Cloudflare Workers | ❌ Admin SDK requires Node.js |
Note: Vercel deploys work fine — the restriction is only when you explicitly opt into the Edge Runtime (export const runtime = 'edge'). The default Node.js serverless runtime on Vercel is fully supported.
Common mistakes
The query requires an indexon verification tokens — You're on a version older than v1.1. Upgradebetter-auth-firestore; the adapter now sorts filtered queries in memory and needs no composite index.- FIREBASE_PRIVATE_KEY with literal
\n— Always call.replace(/\\n/g, "\n")on the key before passing tocert(). - Using at edge runtime — Firebase Admin SDK does not run on Vercel Edge or Cloudflare Workers. Use Node.js runtimes only.
- Deprecated scoped package — Use
better-auth-firestore(unscoped). The@yultyyev/better-auth-firestorepackage is deprecated.
Reporting issues
If behavior still looks like a library bug after checking the mistakes above:
- First confirm the project is on the latest version — many reports (e.g. the composite-index error) are already fixed.
- Only file an issue when the user explicitly asks — never open one autonomously.
- Redact secrets and PII before filing: Firebase project IDs,
FIREBASE_PRIVATE_KEY, tokens, and anycreate_compositeindex URL (it encodes the project path). Include the package version and a minimal repro instead.
Issues: https://github.com/yultyyev/better-auth-firestore/issues