Environment Variables
All environment variables used by Dirework
Dirework's variables come in two flavors: app secrets the app needs to run, and deploy secrets that only matter when deploying to Cloudflare.
Where they live
| Environment | Where to put them |
|---|---|
| Local development | packages/infra/.env — copy it from .env.example. Alchemy loads this file (plus apps/web/.env and apps/server/.env if present) when you run bun run dev. |
| Production | GitHub repository secrets — Settings → Secrets and variables → Actions. The deploy workflow reads them on every push to main. |
App secrets
These are what Dirework itself needs to run:
| Variable | Description |
|---|---|
BETTER_AUTH_SECRET | Secret key for session encryption (min 32 characters — generate with openssl rand -base64 32) |
BETTER_AUTH_URL | The web app's public origin (local: http://localhost:3001, production: https://dirework.<your-subdomain>.workers.dev) |
CORS_ORIGIN | Allowed CORS origin — same value as BETTER_AUTH_URL |
TWITCH_CLIENT_ID | Twitch application client ID from dev.twitch.tv |
TWITCH_CLIENT_SECRET | Twitch application client secret |
In production, BETTER_AUTH_URL and CORS_ORIGIN aren't secrets — they're set at the
top of .github/workflows/deploy.yml. If your workers.dev subdomain isn't
mrdemonwolf, edit those two lines to match yours.
Deploy secrets
Only needed when deploying to Cloudflare (as GitHub secrets, or in your shell for
bun run deploy):
| Variable | Description |
|---|---|
CLOUDFLARE_API_TOKEN | Cloudflare API token with Workers and D1 edit permissions |
ALCHEMY_PASSWORD | Any long random string — encrypts Alchemy's deploy state (openssl rand -base64 32) |
Optional variables
| Variable | Default | Description |
|---|---|---|
DOCS_URL | https://mrdemonwolf.github.io/dirework | URL to your documentation site. Used by the !dwhelp bot command to point viewers at the commands page. |
PRIVACY_POLICY_URL | (unset) | URL to your Privacy Policy page. When set, a link appears in the web app's footer. |
TERMS_OF_SERVICE_URL | (unset) | URL to your Terms of Service page. When set, a link appears in the web app's footer. |
SKIP_ENV_VALIDATION | (unset) | Set to "true" during CI or builds to skip env validation when runtime secrets aren't available. You won't need this locally. |
The legal-page URLs are read by the web worker; set them in apps/web/.env for
local development. If neither is set, the footer's legal links row is simply hidden.
Access to Dirework is single-owner: the first Twitch account to sign in claims the instance, and no one else can take it over. There's no separate allowlist to configure.
Example packages/infra/.env
# Authentication (min 32 chars — generate with: openssl rand -base64 32)
BETTER_AUTH_SECRET="<your-secret-here>"
# Public URL of the WEB worker (the browser-facing origin)
BETTER_AUTH_URL="http://localhost:3001"
# CORS allowed origin (same as BETTER_AUTH_URL)
CORS_ORIGIN="http://localhost:3001"
# Twitch OAuth (from dev.twitch.tv)
TWITCH_CLIENT_ID="your_client_id_here"
TWITCH_CLIENT_SECRET="your_client_secret_here"
# Documentation site URL (used by the !dwhelp bot command)
# DOCS_URL="http://localhost:4000"Production notes
For production deployments:
- Generate fresh secrets for production — never reuse the ones from your computer
BETTER_AUTH_URLandCORS_ORIGINmust point at your web worker (https://dirework.<your-subdomain>.workers.dev) — set in.github/workflows/deploy.yml- There is no
DATABASE_URL— the D1 database is created and bound automatically by Alchemy - Update the Twitch OAuth redirect URLs to match your workers.dev domain (see Twitch OAuth Setup)