Configuration & Local Dev
Two practical things you need before running Auther: which environment variables it reads, and how to bring up a working instance locally. This page is the lookup table for both — keep it open while you configure a deployment or wire up the dev stack.
Configuration reference
Section titled “Configuration reference”Auther is configured entirely through environment variables, validated at startup by
a Zod schema in env.ts. The required set covers the auth secret, the database, JWT
issuance, the reference Payload clients, the cron secret, the QStash and Redis
backends, the webhook secrets, and email delivery. Anything missing here fails the
boot, so treat this as the minimum viable config.
Required environment variables
Section titled “Required environment variables”| Variable | Description | Example |
|---|---|---|
BETTER_AUTH_SECRET | Encryption key (min 32 chars). Used for session encryption, JWKS private-key encryption, and webhook-secret encryption. | a-very-long-random-secret-string-here |
BETTER_AUTH_DATABASE_URL | Turso/libSQL connection URL | libsql://your-db.turso.io |
JWT_ISSUER | JWT issuer URL (must match your deployment URL) | https://auth.example.com |
JWT_AUDIENCE | Comma-separated JWT audience values | payload-admin,my-app,my-spa |
PAYLOAD_CLIENT_ID | Confidential client ID | my-confidential-client |
PAYLOAD_CLIENT_SECRET | Confidential client secret (also used as the signup restriction secret) | secret-at-least-32-chars |
PAYLOAD_REDIRECT_URI | Confidential client redirect URL | https://myapp.com/auth/callback |
PAYLOAD_SPA_CLIENT_ID | Public PKCE client ID | my-spa-client |
PAYLOAD_SPA_REDIRECT_URIS | Comma-separated SPA redirect URLs | https://spa.example.com/callback |
CRON_SECRET | Secret for internal cron endpoints (JWKS rotation, trace cleanup) | cron-secret-value |
QSTASH_TOKEN | Upstash QStash token for the webhook queue | eyJ... |
QSTASH_CURRENT_SIGNING_KEY | QStash signature verification key | sig_xxxxx |
UPSTASH_REDIS_REST_URL | Upstash Redis URL for idempotency/rate limiting | https://your-redis.upstash.io |
UPSTASH_REDIS_REST_TOKEN | Upstash Redis auth token | AxxxxxxxxxxxxxxxxxxxQ== |
PAYLOAD_WEBHOOK_URL | Default outbound webhook destination | https://myapp.com/api/webhooks |
PAYLOAD_OUTBOUND_WEBHOOK_SECRET | HMAC secret for outbound webhooks (min 32 chars) | outbound-webhook-secret-32chars |
PAYLOAD_INBOUND_WEBHOOK_SECRET | HMAC secret for inbound webhooks (min 32 chars) | inbound-webhook-secret-32chars |
RESEND_API_KEY | Resend API key for sending emails | re_xxxxxxxxxxxxx |
EMAIL_FROM | Sender email address | noreply@example.com |
EMAIL_FROM_NAME | Sender display name | Auther |
Optional environment variables
Section titled “Optional environment variables”These tune behavior or supply values that are only needed in specific environments (local Docker networking, Vercel deployments, preview origins, key rotation).
| Variable | Description | Default |
|---|---|---|
BETTER_AUTH_DATABASE_AUTH_TOKEN | Turso auth token | (none) |
PRODUCTION_URL | Production deployment URL | Falls back to NEXT_PUBLIC_APP_URL |
NEXT_PUBLIC_APP_URL | Current deployment URL (used for CORS, trusted origins) | http://localhost:3000 |
PAYLOAD_SPA_LOGOUT_URIS | Comma-separated post-logout redirect URLs | (none) |
PAYLOAD_PREVIEW_ORIGIN_PATTERNS | Wildcard patterns for preview deployments (e.g. https://*.vercel.app) | (none) |
QSTASH_URL | QStash API URL (for local dev) | Default QStash cloud URL |
QSTASH_NEXT_SIGNING_KEY | Next QStash signing key (for key rotation) | (none) |
QUEUE_TARGET_BASE_URL | Base URL for queue worker targets (for Docker networking) | (none) |
VERCEL_URL | Auto-set by Vercel deployments | (none) |
SKIP_EMAIL_SENDING | Set to any value to skip actual email delivery (testing) | (none) |
Local development with Docker
Section titled “Local development with Docker”You don’t need cloud accounts for Turso, Upstash, or Resend to develop locally. The
docker-compose.yml stands up the whole system — including local replacements for
each managed dependency — so a fresh checkout runs end to end with one command.
| Service | Port | Purpose |
|---|---|---|
app (Next.js) | 3000 | The Auther application |
libsql | 8080 | Turso-compatible SQLite database |
redis | 6379 | Upstash Redis replacement |
qstash | 8081 | Upstash QStash local server |
mailhog | 8025 (UI), 1025 (SMTP) | Email testing (catches all outbound email) |
webhook-tester | 8082 | Webhook request inspector |
Quick start
Section titled “Quick start”-
Bring the stack up. Development mode hot-reloads the app; production mode builds the app image first.
Terminal window pnpm d:up-devTerminal window pnpm d:up -
Wait for the supporting services to initialize. On startup, the
db-migrateservice runs the Drizzle schema push, and thedb-seedservice creates a test admin user and seeds OAuth clients for testing. -
Sign in at
http://localhost:3000with the seeded admin credentials:email: admin@test.localpassword: admin123 -
Inspect captured email in the Mailhog UI at
http://localhost:8025, and watch outbound webhook deliveries in the webhook-tester on port 8082.
Useful scripts
Section titled “Useful scripts”When you’d rather run the Next.js server directly against your own services, these
pnpm scripts cover the common tasks. Local dev outside Docker requires a populated
.env.local.
pnpm dev # Local dev server (requires .env.local)pnpm db:push # Push schema changes to the databasepnpm db:generate # Generate Drizzle migrationspnpm user:create # Create a user via CLIpnpm auth:test # Test the auth flowpnpm clients:seed # Seed OAuth clientspnpm lint # ESLint + TypeScript type checking