Environment setup

How the Website resolves configuration across local development, preview, and production. Only variable names are listed here — never commit secret values.

Where configuration comes from

The Website reads configuration from three places, depending on whether the code runs at build time or at runtime inside the Worker:

Source When What it provides
wrangler.toml [vars] Worker runtime Per-environment runtime variables and the Service Binding
vite.config.ts define Build time __*__ global constants baked into the client bundle
.dev.vars (local only) Build time (dev) Local-only build-time secrets, loaded into process.env

.env / .env.example exist for local convenience; scripts/build-static.ts also reads .env when present.

Runtime variables (wrangler.toml)

These are available on the Worker env object at runtime and differ per environment ([vars] = production, [env.preview.vars], [env.dev.vars]).

Variable Purpose
NODE_ENV Environment name (production / development)
BASE_URL Canonical origin of the site (used for canonical/redirect logic, sitemap, robots)
API_URL Platform Worker URL — HTTP fallback when the Service Binding is absent
GTM_ID Google Tag Manager container ID
GTAG_ID Google Ads / gtag.js ID
SUBSCRIPTIONS_API_URL App URL (app.swapps.com) for subscription/checkout calls (set in the dev env)

Note

API_URL is the fallback path. In production and preview the Website talks to the Platform Worker through the API_WORKER Service Binding (zero-latency Worker-to-Worker), not over HTTP. See Service bindings.

Service Binding

[[services]]
binding = "API_WORKER"
service = "swapps-worker"

The binding is declared in the default, preview, and dev environments so the Worker-to-Worker path is exercised in each.

Worker secrets (wrangler secret)

These are not in wrangler.toml [vars]; they are set with wrangler secret put and consumed by src/worker.ts (mainly for the blog edge-cache purge webhook):

Secret Purpose
CACHE_API_SECRET Shared secret authenticating the WordPress blog-cache purge webhook
CF_ZONE_ID swapps.com zone id, target of the global cache purge
CF_PURGE_TOKEN Scoped Cloudflare API token (Zone → Cache Purge) for global eviction

Build-time constants (vite.config.ts)

These are substituted into the bundle at build time via Vite define and read from process.env (or fall back to a default). They are exposed in code as global __*__ constants.

Constant Sourced from process.env
__BASE_URL__ BASE_URL
__API_URL__ API_URL
__GTM_ID__ GTM_ID
__GTAG_ID__ GTAG_ID
__NODE_ENV__ NODE_ENV
__SUBSCRIPTIONS_API_URL__ SUBSCRIPTIONS_API_URL
__SUBSCRIPTIONS_API_URL_INTERNAL__ SUBSCRIPTIONS_API_URL_INTERNAL (falls back to SUBSCRIPTIONS_API_URL)
__RECAPTCHA_SITE_KEY__ RECAPTCHA_SITE_KEY
__CHAT_API_KEY__ CHAT_API_KEY
__SENTRY_DSN__ SENTRY_DSN

Warning

Empty strings are treated as "not set" and fall back to the default. This is why vite.config.ts uses || (not ??) for these defines: an empty API_URL= in .env must fall through to the default rather than producing a broken URL.

Local-only build-time secrets (.dev.vars)

vite.config.ts loads .dev.vars into process.env only if the file exists, so values like RECAPTCHA_SITE_KEY get baked into the client bundle during local builds. In CI/production there is no .dev.vars file, and the build uses the environment as-is. dotenv does not override already-set variables, so shell/CI env always wins.

Environments at a glance

NODE_ENV BASE_URL API_URL
Production ([vars]) production https://swapps.com https://swapps-worker.swapps.workers.dev
Preview ([env.preview.vars]) production https://{alias}-swapps-client.swapps.workers.dev https://swapps-worker.swapps.workers.dev
Development ([env.dev.vars]) development http://localhost:3000 http://localhost:8787

Local API setup

For full local development, run the Platform Worker so API_URL resolves:

cd ../swapps-worker
npm run dev   # wrangler dev on port 8787

If the Platform Worker is not running, blog and lead endpoints will fail over the HTTP fallback — expected behavior locally.

Next steps