Documentation · Managing your service

Environment variables and secrets

Setting variables on the service, keeping tokens out of your code and your images, and the difference that catches everyone.

Updated 2026-09-25 · 5 min read

Environment variables are how configuration reaches your application. They also determine what happens to a secret the moment you leak one, so this page covers both.

Setting them on the service

Environment variables live on the Startup tab of your service, alongside the startup command. Define them there rather than in a file, and they are available to your process automatically.

NODE_ENV=production
PORT=3000
DATABASE_URL=postgres://user:pass@host:5432/db
DISCORD_TOKEN=...

Read them with your runtime's convention:

const token = process.env.DISCORD_TOKEN;        // Node.js
token = os.environ["DISCORD_TOKEN"]              # Python
token := os.Getenv("DISCORD_TOKEN")              # Go

Always provide a fallback or validate at startup. A missing variable should produce a clear error at boot, not an undefined discovered mid-request.

The difference that catches everyone

In shell syntax export DISCORD_TOKEN=... sets the variable in the shell. A startup command is not a shell script — it is a single command run directly. Writing export there produces either an error or a command that does not do what you meant.

Put the assignment in the variables field, and leave the startup command as just the command:

# Wrong — the startup command is not a shell
export DISCORD_TOKEN=abc123 && node index.js

# Right — DISCORD_TOKEN is defined as a variable on the service
node index.js

If you genuinely need chaining inside the startup command, that is a shell — write it into a script file and execute that instead, which is far easier to read than a one-line chain.

Never commit secrets

  • Not in the repository. Add .env to .gitignore and keep a committed .env.example listing variable names with empty values.
  • Not in the image. Anything in a layer is permanent and readable by anyone who pulls the image, including layers a later stage appears to have overwritten. Declare variables in the image; supply values on the service.
  • Not in the console. Printing a token to the log writes it to somewhere far more people can read than the code does.

Rotating a leaked secret

If a token is exposed, revoking and reissuing it is the only real remedy — cleaning it out of the code does not un-expose it. Rotate the credential at its provider, update the variable on the service, and restart.

Order matters: issue the new credential first, then update and restart. Revoking first causes downtime between the revocation and the restart, and if the restart fails you have an outage instead of a rotation.

Defaults and validation

Parse and validate once at startup, then pass the parsed value through your app. Reading process.env throughout the codebase makes every read site a place the variable could be wrong or missing.

const config = {
  token: requireEnv("DISCORD_TOKEN"),
  port: Number(requireEnv("PORT")),
};

function requireEnv(name) {
  const value = process.env[name];
  if (!value) {
    throw new Error(`Missing required environment variable: ${name}`);
  }
  return value;
}

Failing at boot with one clear message beats starting successfully and erroring on every request.

These guides describe behaviour that is common across container platforms. Where a setting is specific to your service — your assigned port, your SFTP credentials, your startup command — it is shown in the panel rather than here, so check the Startup and Files tabs for your own values.

Found an error or something unclear? Let us know so we can correct it.