Most environment variables consumed by the public site and workspace are declared in
packages/lib/src/config/env.ts as a Zod schema that validates at boot — missing required
vars cause loud startup failures rather than silent runtime ones. A handful of vars are still
read directly via process.env (e.g. FRASE_WEBHOOK_API_KEY in proxy.ts); these are called
out below. The Partner Portal (apps/partners) keeps its own vars entirely outside this schema.
Re-export shims live at
lib/config/env.ts(legacy@/lib/config/envimports). Prefer importing via either path over readingprocess.env.Xdirectly — direct access bypasses validation and producesunknown-typed values.
NEXT_PUBLIC_* — bundled into the browser. Safe for anything the client must see.| Variable | Required | Default | Notes |
|---|---|---|---|
NODE_ENV | yes | development | One of development / production / test. |
NEXT_PUBLIC_MATTERS_APP_ENV | yes | development | App-level env flag (separate from NODE_ENV so previews can act like prod). |
NEXT_PUBLIC_API_URL | no | — | Optional base URL for self-fetches. |
All three are .optional() in the schema — "required" here is an operational requirement on
workspace, not a boot-time constraint enforced by Zod.
| Variable | Required | Notes |
|---|---|---|
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY | optional in schema; required on workspace | Public Clerk key. |
CLERK_SECRET_KEY | optional in schema; required on workspace | Server-side Clerk key. |
CLERK_WEBHOOK_SECRET | optional in schema; required on workspace | Svix signature verification for the Clerk webhook. |
| Variable | Required | Default | Notes |
|---|---|---|---|
NEXT_PUBLIC_WORKSPACE_URL | no | https://workspace.matters.ai | Read by lib/workspace-url.ts. Override locally (http://localhost:4001) for dev. |
WORKSPACE_SUBDOMAIN_URL | no | unset | Set this on the public-site Vercel project to activate the gated /workspace/* and /auth/* permanent redirects. |
| Variable | Required | Notes |
|---|---|---|
MONGODB_CONNECTION_STRING | yes | Full Atlas URI. Used by every app that reads/writes leads, audit logs, glossary analytics, etc. |
DATABASE_URL | no | Optional legacy/auxiliary DB. |
| Variable | Required | Notes |
|---|---|---|
WORDPRESS_URL | yes | Public WordPress base URL (e.g. https://content.matters.ai). |
WORDPRESS_HOSTNAME | yes | Bare hostname for Next.js remotePatterns. |
WORDPRESS_WEBHOOK_SECRET | no — defaults to a placeholder (min 32 chars) | Signs incoming WordPress webhook payloads. Has a .default("runtime-placeholder-secret-min-32-chars"), so absence won't crash boot — but webhook verification fails until you set a real secret. |
WORDPRESS_API_URL | no | Optional override if API path differs. |
WORDPRESS_USERNAME | conditional | Required for writes (downloads-config saving, page mutations). |
WORDPRESS_APP_PASSWORD | conditional | Pair with the username. App password, not user password. |
WORDPRESS_CACHE_DURATION | no | Seconds; in-memory cache TTL for WP fetches. |
| Variable | Required | Notes |
|---|---|---|
EMAIL_PROVIDER | no (default ses) | One of ses / smtp. |
AWS_SES_REGION | conditional | When EMAIL_PROVIDER=ses. |
AWS_SES_ACCESS_KEY_ID | conditional | When EMAIL_PROVIDER=ses. |
AWS_SES_SECRET_ACCESS_KEY | conditional | When EMAIL_PROVIDER=ses. |
AWS_SES_FROM_EMAIL | conditional | Verified SES identity. |
AWS_SES_CONFIGURATION_SET | no | SES config set for deliverability tracking. |
SMTP_HOST / SMTP_PORT / SMTP_USER / SMTP_PASS / SMTP_SECURE / SMTP_FROM_EMAIL | conditional | When EMAIL_PROVIDER=smtp. |
RESEND_API_KEY | no | Kept for rollback path. |
| Variable | Required | Notes |
|---|---|---|
SLACK_DEMO_WEBHOOK_URL | yes | Demo-request notifications. |
SLACK_CAREERS_WEBHOOK_URL | no | Job application notifications. |
| Variable | Required | Notes |
|---|---|---|
SALESFORCE_WEB_TO_LEAD_URL | no | Without this, Salesforce sync is disabled. |
SALESFORCE_ORG_ID | no | Org identifier. |
SALESFORCE_RETURN_URL | no | Web-to-Lead return URL. |
SALESFORCE_CAPTURE_PAGE_ID | no | Tracks which page captured a lead. |
SALESFORCE_DEBUG | no (default false) | Logs Salesforce payloads. |
SALESFORCE_DEBUG_EMAIL | no | Routes debug submissions to a single inbox. |
SALESFORCE_DIAL_CODE_FIELD_ID | no | Custom field ID for phone dial codes. |
| Variable | Required | Notes |
|---|---|---|
NEXT_PUBLIC_MUX_ENV_KEY | no | Mux Data env key (client analytics). |
NEXT_PUBLIC_MUX_BEACON_DOMAIN | no | Override Mux Data beacon domain. |
NEXT_PUBLIC_DISABLE_MUX_ANALYTICS | no | Set to "true" to disable analytics calls. |
MUX_ACCESS_TOKEN | conditional | Server-side Mux access. |
MUX_SECRET_KEY | conditional | Server-side Mux secret. |
| Variable | Required | Notes |
|---|---|---|
UPSTASH_REDIS_REST_URL | no | Used for glossary analytics + caching. |
UPSTASH_REDIS_REST_TOKEN | no | Pair with the URL. |
| Variable | Required | Notes |
|---|---|---|
SENTRY_AUTH_TOKEN | no | Source-map upload during build. |
NEXT_PUBLIC_OBSERVABILITY_ENABLED | no (default true) | Master flag. |
NEXT_PUBLIC_MINIMAL_TRACKING | no (default false) | Reduces analytics payload size. |
NEXT_PUBLIC_ENABLE_LOGGING | no (default false) | Verbose logging in the browser console. |
NEXT_PUBLIC_LOG_LEVEL | no (default info) | debug / info / warn / error. |
NEXT_PUBLIC_MICROSOFT_CLARITY_ID | no | Microsoft Clarity ID for session replays. |
| Variable | Required | Notes |
|---|---|---|
MAILERLITE_API_KEY | no | Newsletter integration. |
MAILERLITE_GROUP_WEBINAR_ID | no | Default group for webinar registrants. |
| Variable | Required | Notes |
|---|---|---|
GLOSSARY_CRON_SECRET | conditional — optional in schema (min 16 chars when set) | Shared secret for Vercel Cron → /api/glossary/cron/* endpoints. Required only if the glossary cron jobs are enabled. |
| Variable | Required | Notes |
|---|---|---|
GEMINI_API_KEY | no | Required only if Gemini features are enabled. |
RECAPTCHA_SECRET_KEY | no | reCAPTCHA v2 secret. |
RECAPTCHA_V3_SECRET_KEY | no | reCAPTCHA v3 secret. |
NEXT_PUBLIC_RECAPTCHA_SITE_KEY / NEXT_PUBLIC_RECAPTCHA_V3_SITE_KEY | no | Public reCAPTCHA keys. |
GA4_PROPERTY_ID / GSC_SITE_URL / PAGESPEED_API_KEY | no | Google APIs for SEO automations. |
NEXT_PUBLIC_GOOGLE_SITE_VERIFICATION / NEXT_PUBLIC_BING_SITE_VERIFICATION / NEXT_PUBLIC_YANDEX_VERIFICATION | no | Search engine site-verification meta tags. |
NEXT_PUBLIC_RB2B_SITE_KEY | no | rb2b.com visitor identification site key. |
NEXT_PUBLIC_RB2B_ENABLED | no | Toggle for rb2b tracking. |
NEXT_PUBLIC_RB2B_DEBUG | no | Verbose rb2b logging. |
RATE_LIMIT_MULTIPLIER | no | Scales rate-limit budgets globally. |
RECAPTCHA_V3_MIN_SCORE | no | Minimum reCAPTCHA v3 score to accept a submission. |
WORDPRESS_CONTACT_ENDPOINT | no | Override URL for the WordPress contact-form forwarder. |
SLACK_RESOURCES_WEBHOOK_URL | no | Resource-download notifications. |
SLACK_CONTACT_WEBHOOK_URL | no | Contact-form notifications. |
SLACK_GENERAL_WEBHOOK_URL | no | General-purpose Slack notifications. |
FRASE_WEBHOOK_API_KEY | no | Optional API key for the AI-crawler tracking webhook. Not in the Zod schema — read directly via process.env in proxy.ts. |
apps/partners)#The Partner Portal is a fully separate Next.js app (pinned next@^16.2.9) with its own Clerk
app, its own Neon database project, and its own Salesforce integration user. None of these
vars are shared with workspace or memo. All are declared directly via process.env (no
shared lib schema).
| Variable | Required | Notes |
|---|---|---|
NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY | yes | Public key for the Partners Clerk app (different from workspace). |
CLERK_SECRET_KEY | yes | Server key for the Partners Clerk app. |
CLERK_WEBHOOK_SECRET | yes | Svix signature secret for /api/webhooks/clerk. |
| Variable | Required | Notes |
|---|---|---|
PARTNERS_NEON_DATABASE_URL | yes | Full Neon connection string. Air-gapped from workspace/memo. Run pnpm db:push after setting. |
| Variable | Required | Notes |
|---|---|---|
SF_CLIENT_ID | yes | Connected App consumer key. |
SF_PRIVATE_KEY | yes | RSA private key PEM, base64-encoded. Matching public cert uploaded to SF Connected App. |
SF_USERNAME | yes | Dedicated integration user (not a human login). |
SF_LOGIN_URL | yes | https://test.salesforce.com (sandbox) or https://login.salesforce.com (prod). |
SF_CALLOUT_HMAC_SECRET | yes | HMAC-SHA256 secret for verifying inbound SF push-callout events at /api/sf/callout. Set identically in the SF Named Credential custom header. Generate: openssl rand -hex 32. |
| Variable | Required | Notes |
|---|---|---|
R2_ACCOUNT_ID | yes | Cloudflare account ID. |
R2_ACCESS_KEY_ID | yes | R2 API token with Object Read & Write scope. |
R2_SECRET_ACCESS_KEY | yes | R2 API token secret. |
R2_BUCKET_PARTNERS | yes | Bucket name (e.g. matters-partners). |
R2_PUBLIC_URL | yes | Public base URL for served assets (e.g. https://partners-assets.matters.ai). |
NEXT_PUBLIC_R2_PUBLIC_URL | yes | Public base URL for asset preview in the browser (same value as R2_PUBLIC_URL). Needed by the logo upload component. |
| Variable | Required | Notes |
|---|---|---|
RESEND_API_KEY | yes | Resend API key. |
RESEND_FROM_EMAIL | yes | Verified sender address (e.g. partners@matters.ai). |
| Variable | Required | Notes |
|---|---|---|
UPSTASH_REDIS_REST_URL | yes | Used on /api/sf/callout and auth routes. |
UPSTASH_REDIS_REST_TOKEN | yes | Pair with URL. |
| Variable | Required | Notes |
|---|---|---|
SENTRY_DSN_PARTNERS | yes (prod) | Partners-specific Sentry DSN. |
SENTRY_AUTH_TOKEN | no | Source-map upload during build. |
| Variable | Required | Notes |
|---|---|---|
CRON_SECRET | yes | Bearer secret for Vercel Cron → /api/cron/* routes. Generate: openssl rand -hex 32. |
| Variable | Required | Notes |
|---|---|---|
NEXT_PUBLIC_APP_URL | yes | e.g. https://partners.matters.ai. |
NEXT_PUBLIC_MULTI_ACCOUNT_ENABLED | no | Multi-account UI flag; also gates sendDefaultPii in the Sentry configs. |
MATTERS_CLERK_ORG_ID | conditional | Matters.AI Clerk org ID used by the Super Admin dual-path auth + bootstrap:super-admin script. |
SUPER_ADMIN_EMAILS | conditional | Comma-separated allowlist that grants Super Admin without org membership; read by bootstrap:super-admin. |
The middleware host gate is not env-driven — the accepted hostnames are hardcoded (
new Set(["partners.matters.ai"])) inapps/partners/middleware.ts, so there is noALLOWED_HOSTSenv var. LikewiseNEXT_PUBLIC_CLERK_PUBLISHABLE_KEYandSENTRY_AUTH_TOKENare consumed implicitly by the Clerk and Sentry SDKs respectively, not read viaprocess.envin app code.
CLERK_WEBHOOK_SECRET and the
workspace-only RBAC config (which is reading the codebase, not env vars). Needs the Clerk
publishable/secret keys for shared SSO once cookie domain is set.NEXT_PUBLIC_CLERK_PUBLISHABLE_KEY, CLERK_SECRET_KEY,
PARTNERS_NEON_DATABASE_URL. Cron + SF needed for full functionality.NODE_ENV=production and you're done.