Search

Search Kavel...

Documentation menu

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

Modules degrade gracefully. Without 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, development or production. Locally it is development; deployed Workers set it to production, which disables the interactive /rpc/docs API reference.
  • `WEB_URL` The public URL of the web app, http://localhost:3000 in development. Used for CORS and for building links in emails and auth callbacks.
  • `API_URL` The public URL of the API Worker, http://localhost:8787 in 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.

Email

  • `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 with wrangler secret put NAME or in the Cloudflare dashboard. They never touch the repo.
  • Plain vars, the non-sensitive ones (ENVIRONMENT, WEB_URL), live in wrangler.jsonc under vars.
bash
wrangler secret put BETTER_AUTH_SECRET
wrangler secret put RESEND_API_KEY

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:

ts
export const Config = {
  brand: {
    name: "My App",
    tagline: "Ship faster on the edge",
    domain: "myapp.com",
    email: "hello@myapp.com",
    socialMedia: [
      { id: "github", name: "GitHub", url: "https://github.com/my-app" },
    ],
  },
};

Regenerating types

After changing Worker bindings in wrangler.jsonc, regenerate the Cloudflare types so the API stays type-safe:

bash
bun cf-typegen