Environment variables
Start from .env.example in the repository root — copy it to .env (or
.env.local) and fill in the placeholders. Generate secrets with
openssl rand -hex 32.
The Next.js app reads apps/web/.env.local, because next dev and the
production server run with apps/web as their working directory. The root
.env / .env.local files reach root-level scripts (db:migrate, db:seed,
scripts/*) and the E2E harness. In most setups you keep both in sync.
Tables below list Required as it's presented in .env.example: variables that
ship uncommented in the template are needed for a normal deployment; variables
commented out with # are optional and the app runs without them.
Platform AI
These configure the platform-wide LLM fallback — used only when a workspace has no matching provider configured under Settings → LLM Providers. Tenant provider keys are never stored in the environment; they live encrypted in the database. See bring your own LLM.
| Name | Required | Description |
|---|---|---|
OPENAI_API_KEY | Yes | Platform fallback API key |
OPENAI_MODEL | Yes | Default chat model for the platform fallback |
OPENAI_BASE_URL | No | Optional OpenAI-compatible gateway/proxy endpoint (also used by the local E2E mock). Third-party gateways that only implement /chat/completions and /embeddings cannot back this fallback, since @ai-sdk/openai@4 calls /responses — configure those providers per workspace instead |
OPENAI_VISION_MODEL | No | Override the vision-capable model (defaults to gpt-5.4-nano) |
OPENAI_AGENT_CREATOR_MODEL | No | Override the model used by the agent-creation assistant (defaults to gpt-5.4-nano) |
OPENAI_EMBEDDINGS_MODEL | No | Override the embeddings model (defaults to text-embedding-3-small). Stored vectors must be 384, 768, 1024, or 1536 dimensions |
Application and auth
Core application URL, session signing, and access-control secrets.
| Name | Required | Description |
|---|---|---|
NEXT_PUBLIC_APP_URL | Yes | Canonical app URL and Better Auth callback base — a mismatch with the port the app is served on breaks sign-in |
BETTER_AUTH_SECRET | Yes | Server-side session signing secret |
AUTH_GOOGLE_ID, AUTH_GOOGLE_SECRET | No | Google sign-in is enabled only when both are set; leave unset to disable it |
ACCESS_GATE_SECRET | Yes | Hashes access passwords and signs access cookies for password-gated public agents |
ENCRYPTION_KEY | Yes | Current AES-256-GCM master key for tenant LLM, OAuth, and channel credentials; use a strong environment-specific value |
ENCRYPTION_KEYS_OLD | No | Comma-separated retired master keys kept temporarily for decrypt-only access during rotation; remove each after affected values have been re-sealed |
CRON_SECRET | Yes | Authenticates scheduled and background endpoints |
RATE_LIMIT_SALT | Yes | HMAC salt for anonymous-request rate-limit identifiers; use a different value per environment. ENCRYPTION_KEY is a fallback, but a dedicated salt keeps the two purposes independent |
MONTHLY_MESSAGE_LIMIT | No | Optional monthly workspace message cap; omit for unlimited self-hosted usage |
PUBLIC_CHAT_RATE_LIMIT_WINDOW_MS, PUBLIC_CHAT_SESSION_RATE_LIMIT, PUBLIC_CHAT_ADDRESS_RATE_LIMIT, PUBLIC_CHAT_AGENT_RATE_LIMIT | No | Fixed-window rate limits for the public chat endpoint (per session, per address, per agent), stored in Postgres |
PUBLIC_REVIEW_RATE_LIMIT_WINDOW_MS, PUBLIC_REVIEW_SESSION_RATE_LIMIT, PUBLIC_REVIEW_ADDRESS_RATE_LIMIT, PUBLIC_REVIEW_AGENT_RATE_LIMIT | No | Same, for the public review-generation endpoint |
SMOKE_TEST_SECRET | No | Enables the model-backed /api/smoke route, which is otherwise disabled. Configure only in CI or a private diagnostic environment — never as a health check |
NEXT_PUBLIC_AUTH_GOOGLE also exists in .env.example, but it is a
build-time-only value read by CI (ci-build.yml) and deploy-cloudrun.yml as
a build arg — application code never reads it. Google sign-in is controlled
entirely by whether AUTH_GOOGLE_ID / AUTH_GOOGLE_SECRET are set.
Data and storage
Postgres connection roles and S3-compatible object storage.
| Name | Required | Description |
|---|---|---|
DATABASE_URL | Yes | App role connection string, subject to row-level security. Used by the Next.js app and workers |
DATABASE_MIGRATE_URL | Yes | Migrate role connection string, BYPASSRLS. Used by drizzle-kit and the seed script, and at request time by admin-panel API routes (via getMigrateDb(), gated behind requireSuperAdmin()) — not only an offline migration credential |
DATABASE_POOL_MAX | No | Optional application connection-pool size (defaults to 10) |
S3_ENDPOINT | Yes | S3-compatible storage endpoint (MinIO in dev; your S3/R2/B2/etc. endpoint in production) |
S3_REGION | Yes | Storage region |
S3_BUCKET | Yes | Storage bucket name |
S3_ACCESS_KEY_ID, S3_SECRET_ACCESS_KEY | Yes | Storage credentials |
S3_FORCE_PATH_STYLE | Yes | true for MinIO; false for AWS S3 / Cloudflare R2 / etc. (virtual-hosted style) |
Integrations
Webhook, messaging-channel, and third-party OAuth configuration. WhatsApp and Instagram accounts are configured per workspace and stored encrypted in the database — only the webhook verification secrets below belong in the environment.
| Name | Required | Description |
|---|---|---|
WHATSAPP_INBOX_VERIFY_TOKEN | Yes | Webhook verification token for the WhatsApp inbox. See WhatsApp |
INSTAGRAM_INBOX_VERIFY_TOKEN | Yes | Webhook verification token for the Instagram inbox. See Instagram |
META_APP_SECRET | Yes | Meta app secret, used for webhook signature verification |
NEXT_PUBLIC_META_APP_ID | No | Meta app identifier used by the inbox onboarding UI |
NEXT_PUBLIC_FB_LOGIN_CONFIG_ID | No | Facebook Login config ID used by the inbox onboarding UI |
GOOGLE_CALENDAR_CLIENT_ID, GOOGLE_CALENDAR_CLIENT_SECRET | Yes | Google Calendar OAuth client. See Google Calendar |
GOOGLE_SHEETS_CLIENT_ID, GOOGLE_SHEETS_CLIENT_SECRET | No | Dedicated Google Sheets OAuth client; falls back to the Calendar client credentials when unset. See Google Sheets |
GOOGLE_SERVICE_ACCOUNT_KEY | Yes | Service-account JSON, read only by scripts/register-risc.ts to register Google Cross-Account Protection (RISC) |
RESEND_API_KEY | No | Enables email delivery for verification, password reset, magic links, and notifications. Without it, these URLs are printed to the server console instead |
NOTIFICATION_EMAIL_FROM | No | Sender identity for application email, e.g. Vibesboard <notifications@yourdomain.com> |
OAuth redirect URIs for Google Calendar and Google Sheets are derived from
NEXT_PUBLIC_APP_URL — do not set them separately.
Legal operator identity
Rendered on the /privacy-policy and /terms-of-service pages. Nothing is
hardcoded, since this repository is public: a baked-in default would be inherited by
every fork, and an unconfigured deployment would name someone else's company as the
data controller. Leave all of these unset for local development. Before accepting
real users, set the values that identify the controller and a privacy contact: GDPR
Article 13 requires identifying the controller, and both Google OAuth verification
and Meta app review check for it. Follow the
privacy and data-rights operations runbook
to establish retention and request-handling processes.
| Name | Required | Description |
|---|---|---|
LEGAL_ENTITY_NAME | No | Operating entity name, e.g. Example AB |
LEGAL_ENTITY_REGISTRATION_NUMBER | No | Company registration number |
LEGAL_ENTITY_VAT_NUMBER | No | VAT number |
LEGAL_ENTITY_ADDRESS | No | Registered address; use | to separate rendered lines, e.g. Example Street 1|111 22 Stockholm|Sweden |
LEGAL_GOVERNING_COUNTRY | No | Governing law country |
LEGAL_FORUM | No | Legal forum, e.g. the Stockholm District Court |
LEGAL_SUPERVISORY_AUTHORITY | No | Data-protection supervisory authority name |
LEGAL_SUPERVISORY_AUTHORITY_URL | No | Supervisory authority URL |
LEGAL_CONTACT_EMAIL | No | Privacy contact address |
LEGAL_SERVICE_HOST | No | Service hostname referenced in the legal documents |
Deployment scripts (not read by the app)
| Name | Required | Description |
|---|---|---|
GCP_PROJECT_ID | No | Read only by scripts/setup-secrets.sh, the GCP secret provisioning helper — not by the application itself |