- The database holds users, sessions, agents, delegations and the audit log. It has to be durable. You choose it with
database.provider. - Secondary storage holds small, short-lived, high-churn values: rate-limit counters, device login codes. It only needs fast reads, writes and an atomic counter. You choose it with
secondaryStorage.
Start from where you deploy
The database, in one paragraph each
sqlite (sql.js). SQLite compiled to WebAssembly. No native build, runs on Node, Bun, Deno and edge runtimes. The whole database lives in memory and the file is rewritten after each write. Good for development, tests and tiny single-process apps. Two processes on one file will overwrite each other, and a read-only or ephemeral filesystem loses the data.
sqlite-native (better-sqlite3). Real SQLite on disk, fast, one process at a time in practice. Needs a native build (install better-sqlite3 yourself). A good fit for a single VPS where you want zero database operations. Back up the file.
postgres. The default recommendation for anything with more than one instance or any real traffic. Needs the pg package. Use a pooler on serverless.
mysql. Choose it when MySQL is what your team already runs. Needs mysql2. Behavior is the same as Postgres for theAuth’s purposes.
d1. Cloudflare D1 through a Worker binding. Use it when the app lives on Workers. Pass the binding instead of a URL.
Setup snippets for each are on Database setup.
Secondary storage, in one paragraph each
The
"database" backend creates one table, theauth_secondary_storage, and increments counters with a single guarded UPDATE, so it is exact on every supported database. Expired rows are removed lazily; run databaseStorage(db).purgeExpired() from a cron if you have a large keyspace.
You can choose per feature. A common production setup on Workers is exact storage for device codes and soft storage for rate limits:
A few rules of thumb
- If you are unsure, use Postgres plus
secondaryStorage: 'database'. It has one moving part and works on every deployment shape except Workers. - Do not use memory for anything you would be upset to lose or to count twice: device codes and rate limits on a deployment with more than one instance.
- Do not put the main database on KV. KV is only an option for secondary storage.
- Moving from
sqliteto Postgres later is a data copy. The table names are the same (theauth_*), so plan a one-off export and import, and runcreateTheAuthagainst the new database first so the tables exist. - The Prisma adapter reads and writes theAuth tables from code that already uses Prisma. It does not replace the choice above. See Prisma.
Related
Database setup
Connection snippets for every provider.
Secondary storage
Interface, adapters and per-feature overrides.
Production checklist
Check storage and everything else before launch.
Troubleshooting
Serverless and edge gotchas.