Algoritmi AI SandboxPractice environment with sample data. Nothing here reaches the production platform.

Environment Variables

How app env vars flow from GitHub secrets into Railway at deploy time.

Apps read environment variables from process.env.X in Railway at runtime. But your app's code, your GitHub repo, and your Railway service are three different places — so the tricky question is "how does a secret I store in GitHub end up in Railway?" This page maps the pipeline.

The Three Places

WhereWhat lives there
GitHub → Settings → Secrets and variablesThe source of truth. secrets for sensitive values, vars for non-sensitive config.
apps/<app>/deploy.config.ymlA mapping that says "Railway variable X gets its value from GitHub key Y."
Railway service environmentWhere process.env.X actually reads from at runtime.

The deploy workflow bridges the three.

The Mapping File

Every app has a deploy.config.yml with a secrets: block. The left side is the variable name your app will see at runtime. The right side is the GitHub key name:

apps/training-tracker/deploy.config.ymlyaml
serviceId: "training-tracker"
rootDir: "apps/training-tracker"
secrets:
SLACK_BOT_TOKEN: "TRAINING_TRACKER_SLACK_BOT_TOKEN"
SLACK_WEBHOOK_URL: "TRAINING_TRACKER_SLACK_WEBHOOK_URL"
SLACK_CHANNEL: "TRAINING_TRACKER_SLACK_CHANNEL"
SLACK_SIGNING_SECRET: "TRAINING_TRACKER_SLACK_SIGNING_SECRET"

At runtime, process.env.SLACK_BOT_TOKEN in the training-tracker app reads the value stored in GitHub as TRAINING_TRACKER_SLACK_BOT_TOKEN.

The Per-App Workflow Passes the Value

Each app's staging/production workflow forwards GitHub values into the reusable deploy workflow:

.github/workflows/deploy-app-training-tracker-production.yml (excerpt)yaml
secrets:
SLACK_BOT_TOKEN: ${{ secrets.TRAINING_TRACKER_SLACK_BOT_TOKEN }}
SLACK_WEBHOOK_URL: ${{ vars.TRAINING_TRACKER_SLACK_WEBHOOK_URL }}
  • Use ${{ secrets.X }} for anything sensitive.
  • Use ${{ vars.X }} for non-sensitive config (e.g. a channel name, a feature flag).

Naming Pattern

To keep GitHub variables collision-free across 30+ apps, prefix with the app name in snake_case:

{APP_NAME_SNAKE}_{VAR_NAME}

Examples: BREAKFAST_TRACKER_SLACK_WEBHOOK_URL, RECRUIT_ASHBY_API_KEY, STAFF_MEAL_TRACKER_OPENAI_API_KEY.

See Naming Conventions.

Adding a New Variable — Checklist

  1. Add the GitHub key (in the correct environment — staging vs production) as a secret or var.
  2. Add the mapping to apps/<your-app>/deploy.config.yml under secrets:.
  3. Forward the value in both deploy-app-<app>-staging.yml and deploy-app-<app>-production.yml.
  4. Trigger a deploy and confirm the variable appears in the Railway service environment.

Auto-Injected Variables (No Mapping Needed)

You don't declare these — the platform provides them:

  • DATABASE_URL — from the environment's database service.
  • AUTH_UI_URL — for every non-auth service.

Opt-In Services (Mapping Required)

File storage and notification email are shared by the platform, but they reach only the apps that ask for them. The values are set once in GitHub Environments. An app turns a service on by mapping its values under secrets: in deploy.config.yml and forwarding its one secret in both deploy workflows. The PR check fails when an app's code and its map disagree.

ServiceValues to mapSecret to forwardHow-to
File storageBUCKET_ENDPOINT, BUCKET_ACCESS_KEY_ID, BUCKET_SECRET_ACCESS_KEY, BUCKET_NAME, BUCKET_REGIONBUCKET_SECRET_ACCESS_KEYFile Storage
Notification emailAPP_EMAIL_API_KEY, APP_EMAIL_FROM, APP_EMAIL_NONPROD_ALLOWLISTAPP_EMAIL_API_KEYApp notification email

Example App (apps/example-app) uses both, so its deploy.config.yml shows the lines to copy.

Auth API secrets and variables (GitHub Environments)

Set on both staging and production before deploying Auth API. Used by deploy-auth-staging.yml / deploy-auth-production.yml:

GitHub keyTypeRailway nameNotes
RESEND_API_KEYSecretRESEND_API_KEYResend API key for the client's verified domain
RESEND_FROM_EMAILVariableRESEND_FROM_EMAILSender address, e.g. [email protected] — must match verified Resend domain
AUTH_SECRETSecretAUTH_SECRETBetter Auth session secret
JWT_PRIVATE_KEY_PEM_ACTIVESecretJWT_PRIVATE_KEY_PEM_ACTIVERSA private key for JWT signing

RESEND_FROM_EMAIL is non-sensitive (a public From address) so store it as a Variable, not a Secret. If magic links fail silently, check Resend domain verification and that RESEND_FROM_EMAIL matches the verified domain.

See also Auth & Access.

App notification email (GitHub Environments)

Apps send notification email from their own sender on mail.<apex>, never from the sign-in sender on login.<apex>. The values live once in the GitHub Environments, and a deploy copies them only onto apps that send email:

GitHub keyTypeRailway nameNotes
APP_EMAIL_API_KEYSecretAPP_EMAIL_API_KEYResend Sending access key restricted to mail.<apex>. Never reuse the sign-in key
APP_EMAIL_FROMVariableAPP_EMAIL_FROMFor example Your Company <[email protected]>
APP_EMAIL_NONPROD_ALLOWLISTVariable (staging)APP_EMAIL_NONPROD_ALLOWLISTComma-separated addresses or @domain entries. Outside production, only these receive mail

An app that sends email maps all three in the secrets: block of its deploy.config.yml (for example APP_EMAIL_API_KEY: "APP_EMAIL_API_KEY"), and its deploy-app-<app>-staging.yml and deploy-app-<app>-production.yml forward the APP_EMAIL_API_KEY secret. The two variables need no forwarding. An app without the map never receives the key, and the PR check fails when an app's code and its map disagree.

Ask Claude

Add a new secret to an app
Claude prompt
My meal-planner app needs a new env var OPENAI_API_KEY at runtime. Walk me through: (1) what GitHub key name to use, (2) the deploy.config.yml mapping, (3) what to add to deploy-app-meal-planner-staging.yml and deploy-app-meal-planner-production.yml. Follow the monorepo naming convention.

Troubleshooting

SymptomUsually means
Variable missing in RailwayGitHub key not set in the right environment, or the workflow forgot to forward it.
Value is emptyReferencing vars.X when value lives in secrets.X (or vice versa).
Wrong variable name in RailwayLeft side of deploy.config.yml is wrong — that's the Railway key.

If you're not sure how to add a GitHub secret, check with a developer before proceeding.

Quiz

Quiz

You added `OPENAI_API_KEY: MEAL_PLANNER_OPENAI_API_KEY` to deploy.config.yml and pushed. The deploy ran, but `process.env.OPENAI_API_KEY` is still undefined at runtime. What did you miss?