Configuration

Environment variables behind the Self-Hosting deployment.

For source development, use Local Setup and the repository's .env.sample. Many values can embed the literal string <subdomain>, which getEnv (utils.ts) replaces with the request tenant at runtime; useful for per-tenant URLs and keys.

Runtime vs build-time

Backend services read everything below from the container environment at startup; restart to apply changes. The Core UI container is different: its entrypoint writes every REACT_APP_* variable into a browser-readable js/env.js at startup, so REACT_APP_* values behave as runtime configuration for erxes/erxes-next-ui even though the same names are baked into the bundle as fallbacks. The standalone apps (client-portal-template, help-center, posclient-front) read NEXT_PUBLIC_* values at their own build or entrypoint time; see their app pages.

Core runtime

Variable Read by Required Default Notes
NODE_ENV All backend + UI Yes none production in deployment; development enables dev remotes, router download, and CORS extras
PORT Each service No 4000 gateway, 3300 core-api, 3301 logs, 3302 automations, 3303+ plugins Per-container override
VERSION core-api, gateway, service discovery No os os or saas; switches /initial-setup, plugin discovery, and charge checks
RELEASE_VERSION Plugin APIs on registration No none Values starting with 3. become the releaseVersion used in plugin UI asset URLs; anything else becomes latest
LOAD_BALANCER_ADDRESS Every backend service Recommended in production derived Address registered in Redis; defaults to http://plugin-<name>-api:<port> in production, http://localhost:<port> in dev
GET_CP_TOKEN core-api Only to enable the route none Shared secret for GET /get-client-portal-token?GET_CP_TOKEN=
TEMPLATE_EXPORT_KEY core-api For template export none Passphrase hashed to the AES-256-GCM key that encrypts template exports

Database

Variable Read by Required Default Notes
MONGO_URL All backend services Yes mongodb://127.0.0.1:27017/erxes?directConnection=true Must reach all replica-set members from the containers; the logs service derives <db>_logs from it
DB_NAME erxes-api-shared (saas) saas only erxes_<organizationId> Tenant database name template
CORE_MONGO_URL backend/saas-migrations scripts For those migrations none Some scripts accept a domain-specific override instead of MONGO_URL

Redis

Variable Read by Required Default Notes
REDIS_HOST All backend services Yes none Shared ioredis client, BullMQ queues, GraphQL pubsub
REDIS_PORT All backend services No 6379 none
REDIS_PASSWORD All backend services When Redis requires auth none Must match the Redis container's requirepass; there is no REDIS_URL
SKIP_REDIS posclient sync utils No none When set, POS config sync throws token not found instead of creating a config for an unknown token

Redis holds service discovery (erxes-service-*, erxesservice:config:*), session tokens (user_token_*), plugin lists (erxes-active-plugins), and every BullMQ queue. Persist it (--appendonly yes) and use noeviction.

URLs, domains, and CORS

Variable Read by Required Default Notes
DOMAIN gateway, core-api, services Yes http://localhost:3000 Public UI origin; also the CORS allow-list anchor and the stored hostname fallback
GATEWAY_URL core-api email links No ${DOMAIN}/gateway Public gateway prefix used in emails, unsubscribe links, webhooks
WIDGETS_DOMAIN gateway, core-api No http://localhost:3200 Widgets origin added to CORS
ALLOWED_DOMAINS gateway, core-api, services No none Extra comma-separated CORS origins
ALLOWED_ORIGINS gateway, core-api, services No none Comma-separated regexes appended to the CORS origin list
CLIENT_PORTAL_DOMAINS logs, automations services No none Extra origins for the background services' CORS
TRUST_PROXY All backend services No loopback, linklocal, uniquelocal Express trust proxy; widen only if your LB appends client IPs

Auth and sessions

Variable Read by Required Default Notes
JWT_TOKEN_SECRET gateway, core-api, plugins Yes SECRET Signs and verifies user, portal, and app JWTs. Change it and keep it identical on every backend service
SAME_SITE core-api No none Set to none to emit cross-site auth cookies where the code supports it
WORKOS_API_KEY, WORKOS_PROJECT_ID core-api For WorkOS SSO none SSO login mutations
OAUTH_DEVICE_VERIFICATION_URI core-api No built-in OAuth device-flow verification page override

Plugin and service selection

Variable Read by Required Default Notes
ENABLED_PLUGINS gateway, core-api, dev scripts For plugins none Comma-separated base names (sales,operation); controls gateway waits and /get-frontend-plugins
ENABLED_PLUGINS_ONLY_API gateway, dev scripts No none Backend-only plugins without frontend remotes
ENABLED_SERVICES scripts/start-api-dev.js Dev only none automations,logs → *-service Nx projects; not read by Docker images
MAX_PLUGIN_RETRY gateway No unlimited Bounds plugin-join and /graphql readiness retries at startup

Gateway tuning

Variable Read by Required Default Notes
APOLLO_ROUTER_PORT gateway No 50000 Loopback port for the internal router
INTROSPECTION gateway No off in production true enables GraphQL introspection in production
GRAPHQL_LIMITER gateway No off When set, applies depth/alias/character limits to /graphql
SUPERGRAPH_POLL_INTERVAL_MS gateway (dev) No 10000 Dev-mode recompose interval
DEBUG_GATEWAY_AUTH gateway No false Verbose auth, proxy, and limiter request logs

Workers and retention

Variable Read by Required Default Notes
LOG_RETENTION_DAYS erxes-api-shared logs schema No 365 TTL index on the _logs database logs collection
REVERT_AUTO_JOURNAL_MAX erxes-api-shared No 1000 Max documents snapshotted per bulk write for the undo journal
SEGMENT_CONCURRENCY_CHANGED / _FORGET / _REBUILD / _RECONCILE logs-service No 10 / 5 / 1 / 3 BullMQ concurrency per segment queue
SEGMENT_RECONCILE_CRON / _TZ / _BATCH / _STEPS, SEGMENT_REBUILD_PAGE, SEGMENT_PREVIEW_BUDGET_MS, SEGMENT_TIME_ZONE segment engine No built-in Segment sweep tuning
TIMEZONE sales board/POS report queries No 0 (hour offset) / UTC Numeric hour offset in sales date math

Email

Variable Read by Required Default Notes
SENDGRID_API_KEY core-api auth emails For SendGrid none Throws SENDGRID_API_KEY is missing in environment when a SendGrid path runs without it
SENDGRID_WEBHOOK_PUBLIC_KEY core-api broadcast trackers For SendGrid event webhooks none Verifies inbound event signatures; a deployment-level key marks the webhook shared
AWS_SES_ACCESS_KEY_ID, AWS_SES_SECRET_ACCESS_KEY, AWS_SES_CONFIG_SET, AWS_REGION broadcast transporter For SES none SES sending path
DEFAULT_FROM_EMAIL erxes-api-shared email No none Fallback sender; COMPANY_EMAIL_FROM system config overrides per tenant
EMAIL_DISPOSABLE_DOMAINS core-api intake No none Extra disposable-domain list
EMAIL_PROVEN_WINDOW_DAYS core-api No 180 Proven-address window
EMAIL_RAMP_TIERS, EMAIL_SOFT_BOUNCE_LIMIT core-api broadcast No built-in tiers / 3 Sending ramp and bounce suppression
MAIL_DOMAIN, MAIL_WORKER_URL, MAIL_WEBHOOK_SECRET, MAIL_TENANT, MAIL_SENDING_ACCOUNT_ID, MAIL_SENDING_API_TOKEN, MAIL_SENDING_DAILY_LIMIT, MAIL_INBOUND_RATE_LIMIT, MAIL_RECEIVE_URL frontline_api mail channel For the mail integration none Cloudflare Email Routing → worker → /mail/receive; see .env.sample and the frontline plugin guide

Frontend runtime (REACT_APP_*)

Set on the core-ui container; injected into window.env at startup and falling back to build-time values:

Variable Default Notes
REACT_APP_API_URL <proto>//<host>/gateway (prod), http://localhost:4000 (dev) Public gateway URL the browser calls; <subdomain> in the value is replaced by the hostname's first label
REACT_APP_IMAGE_CDN_URL none Image CDN base
REACT_APP_GOOGLE_MAP_API_KEY none Maps integration
REACT_APP_HIDE_CORE_MODULES none Hides built-in navigation modules
REACT_APP_SENTRY_DSN, REACT_APP_SENTRY_ENVIRONMENT none Frontend Sentry

Variables on the standalone apps include NEXT_PUBLIC_ERXES_API_URL (client-portal-template, help-center; the latter injects it into env.js via its own docker-entrypoint.sh), NEXT_PUBLIC_ERXES_CP_TOKEN (client-portal-template only), and NEXT_PUBLIC_MAIN_API_DOMAIN, NEXT_PUBLIC_APP_VERSION (posclient-front). Check each app's Dockerfile/entrypoint: a container env override only works where the app injects runtime env; otherwise rebuild after changing them.

Observability

Variable Read by Required Default Notes
SENTRY_DSN, SENTRY_ENVIRONMENT, SENTRY_RELEASE, SENTRY_SERVER_NAME, SENTRY_TRACES_SAMPLE_RATE All backend services No off Sentry error tracing; tag as plugin/service

Not env vars

Storage and upload settings are system configs stored in the database, read via configs.getConfigs: UPLOAD_SERVICE_TYPE, AWS_BUCKET, AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, AWS_COMPATIBLE_SERVICE_ENDPOINT, AWS_FORCE_PATH_STYLE, AWS_PREFIX, GOOGLE_CLOUD_STORAGE_BUCKET, GOOGLE_APPLICATION_CREDENTIALS, GOOGLE_PROJECT_ID, CLOUDFLARE_*, AZURE_STORAGE_*, FILE_SYSTEM_PUBLIC. Set them in Settings → file upload, not in .env.

Operate on one system.

Talk to our team about consolidating your stack onto erxes. 30-minute walkthrough, custom to your org.