Skip to content
All guides

Database

Cloudflare D1 schema, migrations, the repository layer and the in memory test double.

Updated 2026-10-21

Why D1

D1 is SQLite at the edge. It removes a separate database vendor, it is fast enough for the workloads a starter kit targets, and it keeps the whole stack inside one Cloudflare account.

Tables

The schema is deliberately small and explicit.

  • users: accounts, credentials, OAuth metadata and account preferences.
  • oauth_provider_linkages: the link between a provider account and a user.
  • auth_sessions: rotating, revocable session records.
  • password_reset_tokens and email_verification_tokens: single use tokens.
  • subscriptions: the Dodo Payments subscription bound to an account.
  • billing_webhook_events: the idempotency ledger for webhook deliveries.
  • rate_limit_buckets: the durable counters behind the authentication limits.
  • oauth_handoff_tokens: the single use tokens that carry a provider sign in over to a session.

The repository layer

Every read and write goes through a repository interface. The production implementation talks to D1 and the test suite uses an in memory double, so the domain logic never changes when the storage engine does.

src/lib/storage/runtime.tstypescript
export const resolveAuthSessionRecordRepository = () =>
  resolveD1Repositories()?.authSessionRepository ??
  inMemoryAuthSessionRecordRepository;

Migrations

Migrations are plain SQL files under migrations/. They are applied with the Wrangler CLI, so the same file runs locally and in production.

terminalbash
bun run db:migrate:local
bun run db:migrate:remote