Firestore Adapter for Better Auth
The `better-auth-firestore` package provides a robust Firestore adapter for the `Better Auth` authentication library, utilizing the Firebase Admin SDK. Currently at stable version `1.2.2`, it receives frequent updates, with several patch and minor releases in the past few months addressing bugs and adding features. This library acts as a drop-in replacement for `Auth.js` (formerly `NextAuth.js`) Firebase adapter, maintaining a compatible data shape, which simplifies migrations. Its key differentiators include built-in handling for Firestore-specific limitations, such as chunking `IN` queries that exceed the 30-value cap, and providing helper functions like `initFirestore` for easy setup and `generateIndexSetupUrl` for required index creation. It strictly targets Node.js 22+ and is designed for TypeScript projects, shipping with full type definitions. While it handles Firestore data storage, `better-auth-firebase-auth` is recommended for actual Firebase Authentication provider integration.
Common errors
-
ReferenceError: require is not defined
cause Attempting to use CommonJS `require()` in an ES Modules (ESM) environment where only `import` statements are supported.fixRefactor your code to use ES Modules `import` syntax for `better-auth-firestore` and ensure your `package.json` specifies `"type": "module"` if running in Node.js ESM. -
ERR_MODULE_NOT_FOUND: Cannot find module './some-module' resolved with .js extension
cause Node.js ESM resolution failed to find a relative module, often due to missing `.js` extensions in import paths in older versions of the library.fixUpgrade `better-auth-firestore` to `v1.1.4` or later, which includes fixes for ESM compatibility by adding `.js` extensions to relative imports. -
FirebaseError: The query uses an 'in' or 'array-contains-any' clause with more than 30 values. Make sure your 'in' or 'array-contains-any' queries do not exceed this limit.
cause A Firestore query generated by the adapter exceeded the 30-value limit for `IN` clauses.fixUpgrade `better-auth-firestore` to `v1.2.0` or later. This version introduces automatic chunking of `IN` queries to work around this limitation. -
FirebaseError: A required index is missing or out of date. You can create it with the following link: [link to Firebase Console]
cause The necessary composite index for the `verificationTokens` collection (on `token` and `expires`) has not been created in your Firestore database.fixFollow the provided link in the error message, or use `generateIndexSetupUrl` from the package to create the required index through the Firebase Console. Alternatively, create it manually via `verificationTokens` collection, `token` (Ascending), `expires` (Ascending).
Warnings
- breaking The package moved from `@yultyyev/better-auth-firestore` to an unscoped name `better-auth-firestore`. Users of the scoped package must migrate to the new name.
- gotcha Firestore `IN` queries have a hard limit of 30 values. Prior to `v1.2.0`, queries exceeding this limit would fail. The adapter now chunks these queries automatically.
- gotcha This package is ESM-only and requires Node.js 22+ as specified in its `engines` field. Older Node.js versions or CommonJS environments are not supported.
- gotcha Node.js ESM compatibility requires explicit `.js` extensions for relative imports. Versions prior to `v1.1.4` might encounter module resolution errors in certain ESM configurations.
- gotcha A composite Firestore index on the `verification` collection is required for proper functionality. Without it, operations involving verification tokens will fail.
- gotcha Compatibility with `better-auth` versions is important. `better-auth-firestore@1.1.3` introduced explicit support for `better-auth@1.5`, and future `better-auth` major versions may require corresponding `better-auth-firestore` updates.
Install
-
npm install better-auth-firestore -
yarn add better-auth-firestore -
pnpm add better-auth-firestore
Imports
- firestoreAdapter
const firestoreAdapter = require('better-auth-firestore');import { firestoreAdapter } from 'better-auth-firestore'; - initFirestore
import initFirestore from 'better-auth-firestore';
import { initFirestore } from 'better-auth-firestore'; - generateIndexSetupUrl
import { generateIndexSetupUrl } from 'better-auth-firestore';
Quickstart
import { betterAuth } from "better-auth";
import { firestoreAdapter, initFirestore } from "better-auth-firestore";
import { cert } from "firebase-admin/app";
import { getFirestore } from "firebase-admin/firestore"; // Also useful for direct Firestore access
// Initialize Firebase Admin SDK for Firestore.
// Ensure these environment variables are securely managed in production.
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" // Optional: name for the Firebase App instance
});
// Configure Better Auth with the Firestore adapter.
export const auth = betterAuth({
// Additional Better Auth configuration options would go here,
// e.g., providers, callbacks, etc.
secret: process.env.AUTH_SECRET ?? 'super-secret-key-for-development-only', // Required for Better Auth
database: firestoreAdapter({
firestore,
// Optional: Customize collection names if needed.
// These are the default values if not specified:
collections: {
users: "users",
sessions: "sessions",
accounts: "accounts",
verificationTokens: "verificationTokens"
},
// Optional: Define a naming strategy for fields (e.g., 'default' or 'snake_case')
namingStrategy: "default"
})
});
// Example of how to access the initialized auth instance (e.g., in an API route)
async function getUserSession(sessionId: string) {
// In a real application, you would use `auth.getSession()` or similar
// This is just to demonstrate the `auth` object is available.
// const session = await auth.getSession({ req: someRequest });
// console.log("Session:", session);
console.log(`Auth instance initialized with Firestore adapter and sessionId: ${sessionId}`);
// You can also directly interact with Firestore via the 'firestore' object
const userDoc = await firestore.collection('users').doc('someUserId').get();
if (userDoc.exists) {
console.log("Example user data:", userDoc.data());
}
}
// Call the example function (for demonstration purposes, not part of actual quickstart)
getUserSession('example-session-id-123');