Environment Variables

deplo.ai discovers environment variables by reading your code, not just your .env.example. Detected variables are scoped to the frontend or backend, connection-wiring keys are injected automatically, and everything ends up as real env vars on your own Vercel project and Render service.

Detection is code-driven#

During analysis, the scanner walks your repository's actual tree — it works regardless of how the project is structured. Two sources feed the variable list:

  • Every .env* file anywhere in the repo. Example and template files (.env.example, .env.sample, …) contribute keys and safe default values. Real env files (.env, .env.local, …) contribute keys only — their values are never reused, since they may be actual secrets.
  • Source files, scanned for the references your code actually makes: process.env.X, process.env["X"], destructuring from process.env, import.meta.env.X, and Python's os.getenv / os.environ. The scan is bounded (up to 60 files, config/entry-point files prioritised) and skips node_modules, build output, and test files.

A variable referenced in code is marked required by default. A default value from an example file makes it optional (pre-filled); an empty or REQUIRED value in an example file keeps it required.

Scopes: frontend, backend, shared#

Each variable is scoped so it only reaches the side that needs it:

  • Keys with a client-side prefix (NEXT_PUBLIC_, VITE_, REACT_APP_, NUXT_PUBLIC_, GATSBY_, PUBLIC_) are always frontend.
  • Otherwise, scope follows the file where the reference was found: a key read under server/ is backend, one read under client/ is frontend.
  • A key seen on both sides becomes shared and is delivered to both.

At deploy time the backend receives backend-scoped and shared variables (never frontend-only ones), and the frontend receives frontend-scoped and shared variables (never backend-only ones) — so a backend secret can never leak into a client-side build.

Variable categories#

Asked of you#

CategoryExampleBehavior
Required, no valueDATABASE_URLDeployment parks in WAITING_FOR_ENV until you provide a value.
Optional / pre-filledLOG_LEVEL=infoDefault taken from your example env file; override it or leave it as-is.

Never asked of you#

CategoryKeysBehavior
Frontend wiring keysNEXT_PUBLIC_API_URL, VITE_API_URL, …Auto-injected with the live backend URL at deploy time.
Backend wiring keysFRONTEND_URL, CLIENT_URL, CORS_ORIGINRecognized as platform-wired; FRONTEND_URL is set on every backend service.
Platform-managedPORT, NODE_ENV, VERCEL_*, RENDER_*Managed by the hosting providers (or by deplo.ai) — never surfaced.

Auto-injected wiring keys#

The frontend needs the backend's URL, but that URL does not exist until the backend deploys — so deplo.ai injects it for you. Any frontend key matching the pattern client prefix + API/BACKEND/SERVER + URL/URI/HOST/ENDPOINT is detected as a wiring key — NEXT_PUBLIC_API_URL, VITE_API_URL, REACT_APP_BACKEND_URL, PUBLIC_API_BASE_URL, and so on. On top of what your code references, a framework default is always injected:

Frontend frameworkDefault injected key
Next.jsNEXT_PUBLIC_API_URL
Vite (React), Vue, SvelteVITE_API_URL
NuxtNUXT_PUBLIC_API_URL
Astro, SvelteKitPUBLIC_API_URL
GatsbyGATSBY_API_URL
Remix (server-side env)API_URL

In the other direction, the backend service always receives FRONTEND_URL — the frontend's production origin — so your CORS configuration can read it instead of hardcoding a domain. Render also sets PORT; your backend should listen on it. See Best Practices.

server/src/index.ts — CORS wired by deplo.ai
app.use(cors({ origin: process.env.FRONTEND_URL }));
app.listen(Number(process.env.PORT) || 4000, "0.0.0.0");

Providing values#

If any required variable is still empty after analysis, the deployment enters WAITING_FOR_ENV and you receive an email listing the missing keys. You can provide values three ways:

  • Dashboard — the deployment page shows the detected list with required keys first; fill them in and the deployment resumes immediately (it transitions straight to DEPLOYING_BACKEND).
  • CLIdeplo prompts for missing values during a deploy. See the command reference.
  • APIPOST /api/v1/deployments/:id/env with a list of { key, value } pairs. See Deployments API.
Tip
You can pre-fill values on the Configure step (or pass envVars when starting a deployment via the API) — if every required variable already has a value, WAITING_FOR_ENV is skipped entirely.

How values reach the providers#

Values become plain environment variables on infrastructure you own: frontend-scoped and shared variables are upserted onto the Vercel project in your account (production target), and backend-scoped and shared variables are applied to the Render service in your workspace. On redeploys, the backend env set is replaced wholesale with the full intended set, so the service always matches what the deployment record says. You can inspect everything in your own Vercel and Render dashboards at any time.

Security notes#

  • Values you provide are stored on the deployment record (per-deployment, in Postgres) so redeploys and retries can reuse them.
  • The API never echoes values back: GET /api/v1/deployments/:id returns each variable's key and isRequired flag only.
  • Values are never written to deployment logs or server logs.
  • Values found in a committed real .env file are never reused as defaults — only the keys are read. (Don't commit real .env files anyway.)
Warning
Anything prefixed NEXT_PUBLIC_, VITE_, or another client prefix is compiled into the browser bundle and is public by definition. Never put secrets in client-prefixed variables.