Skip to content
You are reading the pinned copy of v1.0, which is also the latest release. Read the latest.

Environment variables

Every variable the engine reads, from the four example files in the repository. The install stepper writes the production files; the development files are the ones nx serve reads on a laptop. A variable marked optional is commented out in the example and read only when set.

  • PORT. Example: 53000.
  • NODE_ENV. development and test are the only labels that unlock a development behaviour; every other label, and none, reads as production. Example: development.
  • API_GLOBAL_PREFIX. Path prefix for every API route. The admin dev proxy forwards /api unchanged and the storefront one prefixes /v1 with /api, so dev uses api too; the e2e harnesses set their own. Example: api.
  • DATABASE_URL. Example: postgresql://postgres:postgres@localhost:55432/merchants_engine_dev.
  • DATABASE_TEST_URL. Example: postgresql://postgres:postgres@localhost:55433/merchants_engine_test.
  • REDIS_HOST. Example: localhost.
  • REDIS_PORT. Example: 56379.
  • REDIS_TEST_HOST. Example: localhost.
  • REDIS_TEST_PORT. Example: 56380.
  • REDIS_PASSWORD. Optional. Set both for a managed Redis; TLS is opt-in with true.
  • REDIS_TLS. Optional. Example: true.
  • BETTER_AUTH_SECRET. Better Auth owns auth and sessions. BETTER_AUTH_SECRET is high-entropy, >= 32 bytes; rotate it when a person who knew it leaves. Example: change-in-production-min-32-bytes-abcde.
  • BETTER_AUTH_URL. The API’s own externally-reachable base URL (used to build email links). Example: http://localhost:53000.
  • AUTH_COOKIE_DOMAIN. Optional. Cross-subdomain session cookie, production only. Leading-dot root domain so the session is shared across the admin / storefront / api subdomains. The stepper leaves it unset: every install proxies /api on the admin host. Example: .shop.example.
  • AUTH_SKIP_EMAIL_VERIFICATION. Optional. 1 lets a new account sign in before it verifies its email. Local and e2e use only. Never set it in production: the API does not refuse it there. Example: 1.
  • LOG_LEVEL. Example: debug.
  • SENTRY_DSN. Optional. Error reporting. Unset, Sentry stays off.
  • SENTRY_TRACES_SAMPLE_RATE. Optional. Example: 0.1.
  • CORS_ORIGIN. CORS - admin dev (53200), admin e2e (53211), storefront dev (53300), storefront e2e (53311). Example: http://localhost:53200,http://localhost:53211,http://localhost:53300,http://localhost:53311.
  • STOREFRONT_PUBLIC_BASE_URL. Public origins. In dev these are the local servers; the stepper writes the deployed origins, and the API refuses to boot in production without them. Example: http://localhost:53300.
  • ADMIN_PUBLIC_BASE_URL. Example: http://localhost:53200.
  • API_PUBLIC_BASE_URL. Example: http://localhost:53000.
  • STOREFRONT_REVALIDATE_URL. Storefront revalidation - backend-to-backend signal that triggers SSR cache invalidation on product / category / CMS write events. Both values must match the storefront’s. The secret is a high-entropy string ≥ 32 bytes. Never log it. Example: http://localhost:53300/api/_internal/revalidate.
  • STOREFRONT_REVALIDATE_SECRET. Example: change-in-production-min-32-bytes-12345.
  • STOREFRONT_REVALIDATE_URL_BASE. Optional. Legacy fallback for the storefront origin in search-engine pings; read only when STOREFRONT_PUBLIC_BASE_URL is unset. Example: http://localhost:53300.
  • STOREFRONT_API_URL. Storefront server. The base URL its SSR calls reach the API on. Example: http://localhost:53000/api.
  • STOREFRONT_MIN_FACET_COVERAGE. Optional. Storefront facets. A facet shows once at least this many products carry it, and only while distinct values divided by covered products stays at or under the spread. Example: 6.
  • STOREFRONT_MAX_FACET_SPREAD. Optional. Example: 0.35.
  • ENABLE_THROTTLE. Optional. Rate limiting. Off under NODE_ENV=test unless ENABLE_THROTTLE is set. Setting DISABLE_THROTTLE to 1 turns it off outside production only. Example: 1.
  • DISABLE_THROTTLE. Optional. Example: 1.
  • TME_FINGERPRINT. Optional. Technology detectors. The engine names itself in a generator meta tag and an X-Powered-By header. off, false, 0 or no removes every marker; major adds the major version. The full version is never sent. Example: off.
  • TME_FINGERPRINT_VERSION. Optional. Example: major.
  • UNSUBSCRIBE_TOKEN_SECRET. Unsubscribe links in outbound mail are signed with this. Example: change-in-production-min-32-bytes-abcdef.
  • UPLOADS_ROOT. Public-served uploads root, relative to the working directory. Example: uploads.
  • MAX_FILE_SIZE. Example: 10485760.
  • ALLOWED_FILE_TYPES. Example: jpg,jpeg,png,gif,pdf,doc,docx.
  • STORAGE_DRIVER. Asset storage - choose driver per environment. local - writes to ./uploads (dev fallback, no S3 needed) s3 - any S3-compatible bucket (set the S3_* vars below) Example: local.
  • S3_ENDPOINT. Optional. Example: https://s3.<region>.example.
  • S3_REGION. Optional.
  • S3_BUCKET. Optional.
  • S3_ACCESS_KEY. Optional.
  • S3_SECRET_KEY. Optional.
  • S3_PUBLIC_URL. Optional.
  • PRIVATE_UPLOADS_DIR. Asset variant pipeline. Local driver - where uploaded originals are written. Must be OUTSIDE the public-served uploads/ root. Defaults to ./uploads-private/. Example: ./uploads-private.
  • SIGNED_URL_SECRET. Secret used by LocalStorageDriver.signUrl() to mint HMAC-signed admin access URLs for private originals. High-entropy ≥ 32 bytes. Example: change-in-production-min-32-bytes-67890.
  • RETAIN_ORIGINALS. Original-deletion gate: true keeps originals for re-processing (dev), false deletes them once every variant is verified (the production default). Example: true.
  • STRIPE_API_KEY. Optional. Stripe keys entered in the admin win; these are the fallback.
  • STRIPE_WEBHOOK_SECRET. Optional.
  • STRIPE_PUBLISHABLE_KEY. Optional.
  • PAYMENT_FAKE_PROVIDERS. Optional. Registers the fake_embedded and fake_redirect providers for the e2e suites. The API refuses to boot with this set when NODE_ENV=production. Example: true.
  • PAYMENT_CONFIG_ENCRYPTION_KEY. Optional. Encrypts payment secrets saved from the admin (AES-256-GCM). 32 random bytes, base64: openssl rand -base64 32. Without it, saving a secret answers 503.
  • PAYMENT_CONFIG_ENCRYPTION_KEYS_PREVIOUS. Optional. Retired keys kept readable after a rotation, comma separated.
  • MAIL_TRANSPORT. Transport selection - console (default, no network) lets local dev + jest + e2e run without a Resend account. resend calls the real API. Example: console.
  • RESEND_API_KEY. Sending-only API key (re_…). REQUIRED when MAIL_TRANSPORT=resend.
  • RESEND_FROM_EMAIL. Envelope-from address. Must be on a Resend-verified domain. Example: noreply@example.test.
  • RESEND_FROM_NAME. Display name combined with RESEND_FROM_EMAIL to build the From: header. Example: My Store.
  • RESEND_REPLY_TO. Default Reply-To header. Per-job overrides take precedence. Example: contact@example.test.
  • CONTACT_FORM_RECIPIENT. Where the storefront contact form is delivered. Example: contact@example.test.
  • RESEND_WEBHOOK_SECRET. Svix signing secret (whsec_…) for inbound webhooks at /api/v1/webhooks/resend. REQUIRED when MAIL_TRANSPORT=resend.
  • MAIL_DEV_REDIRECT_TO. Development override - when set, every email is redirected here. Honoured under NODE_ENV=development and test only; a production boot refuses it.

Sign-up bot protection - Cloudflare Turnstile

Section titled “Sign-up bot protection - Cloudflare Turnstile”
  • TURNSTILE_SECRET. Optional. Leave unset in dev and e2e: the widget stays inert and sign-up stays open.
  • INDEXNOW_KEY. IndexNow key: 8 to 128 lower-case hex characters. The storefront serves the matching key file; the stepper writes it.
  • INDEXNOW_HOST. Optional. Defaults to the storefront host.
  • GSC_SUBMISSION_ENABLED. Google Search Console API (opt-in): Example: false.
  • GSC_SITE_URL. sc-domain:<domain> for a domain property, or https://<domain>/ for a URL-prefix property.
  • GOOGLE_APPLICATION_CREDENTIALS. Absolute path to the service-account JSON key. Never commit the file.
  • BING_API_KEY. Bing Webmaster API (opt-in):
  • BING_SITE_URL. The verified site URL; falls back to STOREFRONT_PUBLIC_BASE_URL.
  • INVOICE_LOGO_PATH. Optional PNG drawn in the invoice header; without it the header carries the store name. The stepper writes it from the uploaded logo.
  • NODE_ENV. Example: production.
  • PORT. Example: 53000.
  • API_GLOBAL_PREFIX. Example: api.
  • LOG_LEVEL. Example: info.
  • TME_FINGERPRINT. Optional. Technology detectors. The engine names itself in a generator meta tag and an X-Powered-By header. off, false, 0 or no removes every marker; major adds the major version. The full version is never sent. Example: off.
  • TME_FINGERPRINT_VERSION. Optional. Example: major.

Database and cache (compose service names)

Section titled “Database and cache (compose service names)”
  • DB_PASSWORD. Example: <generated, 64 hex>.
  • DATABASE_URL. Example: postgresql://merchants_app:<generated>@postgres:5432/merchants_engine?schema=public.
  • REDIS_HOST. Example: redis.
  • REDIS_PORT. Example: 6379.
  • REDIS_PASSWORD. Example: <generated, 64 hex>.
  • BETTER_AUTH_SECRET. Example: <generated, 64 hex>.
  • BETTER_AUTH_URL. The public API origin, used in every callback link inside an email. Example: https://api.shop.example.
  • CORS_ORIGIN. Also Better Auth trustedOrigins. The admin reaches the API through its own origin. Example: https://shop.example,https://admin.shop.example.
  • STOREFRONT_PUBLIC_BASE_URL. Example: https://shop.example.
  • ADMIN_PUBLIC_BASE_URL. Example: https://admin.shop.example.
  • API_PUBLIC_BASE_URL. Example: https://api.shop.example.
  • STOREFRONT_REVALIDATE_URL. Example: https://shop.example/api/_internal/revalidate.
  • STOREFRONT_REVALIDATE_SECRET. Example: <generated, 64 hex; the storefront box needs the same value>.
  • UNSUBSCRIBE_TOKEN_SECRET. Example: <generated, 64 hex>.
  • TURNSTILE_SECRET. Example: <entered and verified against siteverify>.
  • MAX_FILE_SIZE. Example: 10485760.
  • ALLOWED_FILE_TYPES. Example: jpg,jpeg,png,gif,pdf,doc,docx.
  • STORAGE_DRIVER. Example: s3.
  • S3_ENDPOINT. Example: https://s3.<region>.example.
  • S3_REGION. Example: <region>.
  • S3_BUCKET. Example: <bucket, hyphens, no dots>.
  • S3_ACCESS_KEY. Example: <entered and verified by a put, get and delete>.
  • S3_SECRET_KEY. Example: <entered>.
  • S3_PUBLIC_URL. Example: https://<bucket>.s3.<region>.example.
  • SIGNED_URL_SECRET. Example: <generated, 64 hex>.
  • RETAIN_ORIGINALS. Example: false.
  • INVOICE_LOGO_PATH. Example: /app/config/invoice-logo.png.
  • MAIL_TRANSPORT. Example: resend.
  • RESEND_API_KEY. Example: <entered and verified by a domain lookup and a test message>.
  • RESEND_WEBHOOK_SECRET. Example: <entered>.
  • RESEND_FROM_EMAIL. Example: noreply@shop.example.
  • RESEND_FROM_NAME. Example: My Store.
  • RESEND_REPLY_TO. Example: hello@shop.example.
  • CONTACT_FORM_RECIPIENT. Example: hello@shop.example.
  • MAIL_DEV_REDIRECT_TO. Honoured under NODE_ENV=development only; a production boot refuses a non-empty value.
  • INDEXNOW_KEY.
  • BING_API_KEY.
  • BING_SITE_URL.
  • GSC_SUBMISSION_ENABLED. Example: false.
  • GSC_SITE_URL.
  • GOOGLE_APPLICATION_CREDENTIALS.
  • STRIPE_API_KEY.
  • STRIPE_WEBHOOK_SECRET.
  • STOREFRONT_API_URL. API base URL the storefront fetches from. Browser-side proxy rewrites /v1/* to ${STOREFRONT_API_URL}/v1/* (see vite.config.ts). Example: http://localhost:53000/api.
  • STOREFRONT_PUBLIC_BASE_URL. Public base URL the storefront uses for canonical, og:url, hreflang alternates, and JSON-LD URL fields. Production: the deployed origin. Example: http://localhost:53300.
  • STOREFRONT_REVALIDATE_SECRET. Shared secret matched by the API webhook listener. Compared timing-safely on the inbound /api/_internal/revalidate request. Must equal the value of STOREFRONT_REVALIDATE_SECRET on the API side. Rotate it together with the API side. Example: change-in-production-min-32-bytes-12345.
  • REDIS_HOST. Redis client for the inbound /api/_internal/revalidate webhook dedup (the same dedup the API applies to inbound webhooks). The storefront SSR process MUST resolve to a Redis instance in production (the boot guard in apps/storefront/src/server/lib/dedup-store.ts throws when NODE_ENV=production and REDIS_HOST is unset). In local dev these defaults match the dev Redis container on port 56379 per the reserved port table. Leave blank to opt into the in-memory fallback (acceptable for vitest + local single-process work; never for production). Example: localhost.
  • REDIS_PORT. Example: 56379.
  • REDIS_PASSWORD.
  • TME_FINGERPRINT. Optional. Technology detectors. The engine names itself in a generator meta tag and an X-Powered-By header. off, false, 0 or no removes every marker; major adds the major version. The full version is never sent. Example: off.
  • TME_FINGERPRINT_VERSION. Optional. Example: major.
  • NODE_ENV. Example: production.
  • PORT. Example: 54300.
  • HOST. Example: 0.0.0.0.
  • STOREFRONT_API_URL. On one box the storefront reaches the engine over the compose network (http://api:53000/api); on its own box it goes out over the public API origin. Example: https://api.shop.example/api.
  • STOREFRONT_PUBLIC_BASE_URL. Public origin used for canonical, og:url, hreflang, JSON-LD URL fields. Example: https://shop.example.
  • STOREFRONT_REVALIDATE_SECRET. Must equal the engine’s STOREFRONT_REVALIDATE_SECRET; a storefront-only box is asked for it and the engine box prints it at the end of its install. Example: <the engine's value>.
  • VITE_TURNSTILE_SITE_KEY. Public; read at build time and passed by the stepper as a build argument. Example: <entered>.

Revalidate dedup store (compose service names)

Section titled “Revalidate dedup store (compose service names)”
  • REDIS_HOST. Example: redis.
  • REDIS_PORT. Example: 6379.
  • REDIS_PASSWORD. Example: <generated, 64 hex>.
Section titled “Public API origin, for links the page builds itself”
  • API_URL. Example: https://api.shop.example/api.
  • TME_FINGERPRINT. Optional. The engine names itself in a generator meta tag and an X-Powered-By header. off, false, 0 or no removes every marker; major adds the major version. The full version is never sent. Example: off.
  • TME_FINGERPRINT_VERSION. Optional. Example: major.
As seen on Open Source Alternatives The Merchant Engine badge