Configuration
Two things to configure: the secrets for the services you use, and your brand details. This page is the full reference for both.
Where configuration lives
Local secrets live in apps/api/.dev.vars (gitignored). The scaffolder creates it from .dev.vars.example, which lists every variable the modules you selected can use, so you only ever see the variables that apply to your app. Brand details live separately in packages/ui/src/config.ts.
Note
RESEND_API_KEY the email module logs and skips sending; without Stripe keys the checkout endpoints stay dormant. You can build and click around before wiring up a single external service.Core variables
These exist in every Kavel app, whichever modules you pick.
- `ENVIRONMENT` The runtime mode,
developmentorproduction. Locally it isdevelopment; deployed Workers set it toproduction, which disables the interactive/rpc/docsAPI reference. - `WEB_URL` The public URL of the web app,
http://localhost:3000in development. Used for CORS and for building links in emails and auth callbacks. - `API_URL` The public URL of the API Worker,
http://localhost:8787in development. The web app reads it to reach the backend.
Module variables
Each module adds only its own variables to .dev.vars.example. Fill in the ones for the modules you enabled.
Auth
- `BETTER_AUTH_SECRET` Required. Signs sessions and tokens. Generate one with
openssl rand -base64 32. - `GITHUB_CLIENT_ID` and `GITHUB_CLIENT_SECRET` Optional. Turn on GitHub social login, created in your GitHub OAuth app settings.
- `GOOGLE_CLIENT_ID` and `GOOGLE_CLIENT_SECRET` Optional. Turn on Google social login, from the Google Cloud console.
Leave the OAuth pairs empty to keep those providers off. Email and password sign-in works without any of them.
- `RESEND_API_KEY` Required to send. Your Resend API key. Without it the module logs the email and skips delivery.
- `EMAIL_FROM` The From address, for example
My App <noreply@myapp.com>. The domain must be verified in Resend. - `CONTACT_TO` Where contact-form submissions are delivered.
Payments
- `STRIPE_SECRET_KEY` Required. Your Stripe secret key from the Stripe dashboard.
- `STRIPE_WEBHOOK_SECRET` Required. Verifies incoming Stripe webhooks, shown when you register your webhook endpoint.
- `STRIPE_PRICE_ID` The price the checkout charges for.
Local vs production
.dev.vars is for local development only and is never committed. In production the same names split into two kinds:
- Secrets, the sensitive values (API keys,
BETTER_AUTH_SECRET, Stripe keys), are set withwrangler secret put NAMEor in the Cloudflare dashboard. They never touch the repo. - Plain vars, the non-sensitive ones (
ENVIRONMENT,WEB_URL), live inwrangler.jsoncundervars.
Warning
.dev.vars is for local development only. In production, set secrets on the Worker with wrangler secret put NAME, never commit them. See Deployment.Brand configuration
Your name, tagline, contact details, and social links live in one typed object at packages/ui/src/config.ts. Marketing pages, the footer, and email templates read from it, so updating your brand is a single edit:
Regenerating types
After changing Worker bindings in wrangler.jsonc, regenerate the Cloudflare types so the API stays type-safe: