Reference

Configuration reference

Edit page
Customer Portal environment variables, defaults, precedence, secrets, and production checks.

Customer Portal reads deployment settings from the process environment. Copy .env.example for local development, but provide production values through the hosting platform or secret manager.

Environment variables

VariableRequiredDefaultMeaning
DATABASE_URLYesNonePostgreSQL connection string used by the shared Drizzle client and migrations.
PUBLIC_URLProductionhttp://localhost:3051 in .env.examplePublic origin used to construct application links and as the fallback Better Auth origin.
BETTER_AUTH_URLProductionFalls back to PUBLIC_URLCanonical Better Auth server and client origin. It must address the same deployed portal.
BETTER_AUTH_SECRETYesNone in productionHigh-entropy secret used by Better Auth for encryption, signing, and hashing. Use at least 32 characters and keep the same value across application instances.
ADMIN_EMAILSNoEmptyComma-separated, case-insensitive email allowlist for system administrators. Whitespace is trimmed.
RESEND_API_KEYEmail flowsEmptyPlatform Resend credential for authentication messages such as verification and password reset.
RESEND_FROM_EMAILEmail flowsEmptySender used with the platform Resend credential.
PORTAL_GITHUB_ENABLEDNotrueShows and configures GitHub sign-in when both GitHub credentials are also present.
GITHUB_CLIENT_IDGitHub sign-inEmptyGitHub OAuth client identifier.
GITHUB_CLIENT_SECRETGitHub sign-inEmptyGitHub OAuth client secret.
PORTAL_GOOGLE_ENABLEDNotrueShows and configures Google sign-in when both Google credentials are also present.
GOOGLE_CLIENT_IDGoogle sign-inEmptyGoogle OAuth client identifier.
GOOGLE_CLIENT_SECRETGoogle sign-inEmptyGoogle OAuth client secret.
PORTAL_REGISTRATION_MODENoopenAccount policy: open, invitation-only, or disabled. Invalid values fall back to open.
PORTAL_TERMS_URLNo/Link shown from authentication forms for the deployment's Terms of Service.

The provider flags use strict string parsing: only the literal value true enables a flag. Set a provider flag to false when the deployment does not configure that provider.

Generate BETTER_AUTH_SECRET with openssl rand -base64 32; never copy a documentation placeholder into a deployment. See the Better Auth secret reference for the upstream contract.

Runtime variables

These variables belong to Node or the generated Nitro server rather than a Customer Portal feature:

VariableProduction behavior
NODE_ENVSet to production by the Docker image and normal production runtimes. Customer Portal uses it to avoid retaining the development database singleton.
HOSTBind address for the generated server. The Docker image sets 0.0.0.0; use a loopback address only when a local proxy is the sole caller.
PORTListening port for the generated server. Nitro uses port 3000 unless the runtime overrides it.

URL precedence

The authentication server resolves its origin in this order:

  1. BETTER_AUTH_URL;
  2. PUBLIC_URL;
  3. the local development fallback.

Set both URL variables to the same HTTPS origin in production. A mismatch can produce incorrect email links, rejected OAuth callbacks, or session cookies attached to the wrong host. Do not add a trailing path.

.env
PUBLIC_URL=https://portal.example.com
BETTER_AUTH_URL=https://portal.example.com

Registration and administrators

PORTAL_REGISTRATION_MODE controls who may create an account:

ValueBehavior
openAnyone can use the signup flow.
invitation-onlySignup is available only in an organization invitation flow.
disabledPublic signup is unavailable; existing users may still sign in.

ADMIN_EMAILS grants the system-wide administrator role when a listed account registers or signs in. This is separate from the owner, admin, and member roles inside an organization. Limit this list to accounts that genuinely administer the whole installation.

Email ownership

The Resend environment variables belong to the platform and send authentication mail. Organization-owned transactional mail is configured in the portal UI and stored per organization. The timesheets module uses that organization credential for invoices and reminders, so changing the platform Resend key does not replace an organization's sender.

Secret handling

Keep these server-only values out of source control, client runtime configuration, logs, screenshots, and issue reports:

  • DATABASE_URL;
  • BETTER_AUTH_SECRET;
  • RESEND_API_KEY;
  • GITHUB_CLIENT_SECRET;
  • GOOGLE_CLIENT_SECRET;
  • organization email-provider credentials.

Client IDs and public origins are identifiers rather than secrets, but should still be specific to the intended deployment.

Do not rotate BETTER_AUTH_SECRET by simply replacing it on running instances: existing encrypted or signed auth state may depend on the prior value. Plan secret rotation using Better Auth's versioned-secret mechanism and test active sessions and OAuth flows before production rollout.

Production verification

After changing configuration:

  1. restart the application so Nitro reads the new environment;
  2. open the portal at PUBLIC_URL and complete a sign-in;
  3. verify signup matches the configured registration mode;
  4. request an authentication email and inspect its origin and sender;
  5. test each enabled OAuth provider from the public hostname;
  6. confirm a normal member does not receive system-administrator access;
  7. run the deployment checks in Deployment.