Environment Variables and Secrets on App Platforms

Serdar Tekin
Serdar Tekin
Co-Founder & CTO
Updated Oct 17, 202611 min read
Written for: Developers and small teams managing configuration and credentials across app platform environments and services
App PlatformSecretsEnvironment VariablesConfiguration
Last reviewed:
Guide
Environment Variables and Secrets on App Platforms
rafftechnologies.com/learn
On this page

Key Takeaways

Keep configuration outside source code, scope credentials per service and environment, isolate preview secrets, prefer platform bindings where possible, treat rotation as an operational workflow, and review configuration changes like deployments.

Don't have an app yet? Deploy on Raff Apps in minutes.

Environment variables and secrets are the configuration boundary between application code and the environment where it runs.

On an App Platform, this boundary becomes especially important because the same source revision may run in:

  • preview;
  • development;
  • staging;
  • production;
  • worker;
  • cron;
  • one-off jobs.

The source code should remain the same while environment-specific configuration changes.

Raff Technologies Apps supports service configuration and private bindings to databases and buckets. Current product behavior includes scoped per-service credentials and private connections between services and managed databases.

Environment variables and secrets are not the same thing

An environment variable is a delivery mechanism.

The value can be:

  • non-sensitive configuration;
  • a secret.

Examples of normal configuration:

Text
APP_ENV=production LOG_LEVEL=info FEATURE_CHECKOUT_V2=true

Examples of secrets:

Text
DATABASE_PASSWORD=... STRIPE_SECRET_KEY=... SESSION_SECRET=...

Do not call every environment variable a secret.

The handling requirements differ.

Keep environment-specific values out of source code

Avoid:

Js
const dbPassword = "production-password";

Prefer:

Js
const dbPassword = process.env.DATABASE_PASSWORD;

This lets the same artifact run across environments without rebuilding.

It also keeps production values out of Git history.

Configuration should be explicit

A production service should have a documented list of required configuration keys.

Example:

Text
APP_ENV PORT DATABASE_URL OBJECT_STORAGE_BUCKET EMAIL_FROM STRIPE_SECRET_KEY

At startup, validate required values.

Do not allow a missing production secret to silently fall back to a development default.

Scope secrets per service

A multi-service application should not give every process the same secret set.

For example:

Text
web DATABASE_URL SESSION_SECRET worker DATABASE_URL QUEUE_URL EMAIL_API_KEY cron DATABASE_URL BILLING_API_KEY

The image-processing worker does not need the billing credential.

Least privilege applies inside one application stack too.

Use platform bindings when they reduce credential scope

Raff Apps can bind services to managed databases and buckets, injecting scoped per-service credentials over private connections.

This is preferable to copying a master database or bucket credential into every service.

The important security property is:

Compromising one service should not automatically expose every data resource.

Preview environments must not inherit production credentials

Preview deployments are intentionally temporary and may run code from unmerged branches.

Use separate credentials for:

  • preview;
  • staging;
  • production.

A preview environment should not have write access to the production database merely because it was created from the same repository.

This principle also applies to third-party API keys.

Secrets need lifecycle management

A secret has a lifecycle:

Text
create → distribute → use → rotate → revoke

For every important secret, know:

  • who owns it;
  • where it is configured;
  • which services use it;
  • how it rotates;
  • how it is revoked;
  • what breaks during rotation.

A secret that cannot be rotated safely is operational debt.

Rotate without forcing immediate downtime

A common rotation pattern is overlap:

  1. create new credential;
  2. allow old and new temporarily;
  3. update service configuration;
  4. deploy/restart safely;
  5. verify;
  6. revoke old credential.

This is easier when the upstream system supports multiple active credentials.

If only one credential can exist, coordinate deployment and cutover carefully.

Avoid leaking secrets into build logs

Build-time variables can appear in:

  • command output;
  • image layers;
  • cache;
  • CI logs.

Do not pass runtime secrets through Docker build arguments unless the build truly requires them and the mechanism protects them.

Prefer runtime injection.

Logs are a common secret-leak path

Bad:

Js
console.log(process.env);

Bad:

Text
Database connection failed: postgres://user:password@host/db

Log:

  • error type;
  • safe identifiers;
  • operation context.

Redact:

  • tokens;
  • passwords;
  • cookies;
  • authorization headers;
  • signed URLs.

Configuration changes are deployment changes

Changing a secret or environment variable can alter application behavior as much as changing source code.

Treat configuration changes with:

  • ownership;
  • review;
  • rollout;
  • verification;
  • rollback.

If a new code revision requires a new variable, define compatibility between the old and new revisions.

Database URLs often bundle multiple concerns

A database URL may contain:

  • hostname;
  • port;
  • database name;
  • username;
  • password;
  • TLS parameters.

Do not paste it into documentation, issue trackers, or screenshots.

When the platform supplies scoped database bindings, use those instead of manually sharing one administrative URL.

Environment naming should be boring and consistent

Use a small vocabulary:

Text
preview development staging production

Avoid one service using prod, another live, and another production unless there is a clear reason.

Consistency improves automation and incident response.

Separate environment identity from feature configuration

Do not overload APP_ENV with every behavior.

Prefer:

Text
APP_ENV=production FEATURE_NEW_CHECKOUT=false EMAIL_MODE=live

This makes behavior explicit and reduces hidden conditional logic.

Configuration ownership in multi-service apps

For every variable, ask whether it is:

  • global to the app;
  • environment-specific;
  • service-specific;
  • secret;
  • generated by a binding;
  • temporary migration state.

This prevents configuration sprawl.

App Platform secret checklist

Before production:

  • no production secret is committed to Git;
  • required variables are validated at startup;
  • preview/staging credentials are separate;
  • service credentials are least privilege;
  • logs redact secrets;
  • database/bucket bindings are scoped;
  • secret ownership is known;
  • rotation procedure exists;
  • configuration changes are reviewed;
  • rollback compatibility is understood.

Frequently asked questions

Are environment variables secure?

Environment variables are a configuration mechanism, not a security guarantee. Sensitive values still need controlled storage, access, rotation, and logging discipline.

Should every service use the same DATABASE_URL?

Not if separate scoped credentials are available. Give each service only the database permissions it needs.

Should previews use production secrets?

No. Preview environments should use isolated low-privilege credentials and should not write to production data.

Can secrets be committed in a private Git repository?

They should not be. Repository privacy does not provide the same lifecycle, access control, rotation, and audit model as a secret-management system.

How should I rotate a secret?

Prefer overlapping old/new credentials, update the service, verify the new credential, then revoke the old one.

Sources

Was this article helpful?
Serdar Tekin
Serdar Tekin
Co-Founder & CTO

Co-Founder & CTO at Raff, focused on cloud infrastructure, systems architecture, security, reliability, and production operations.

Put it into practice

Spin up a Raff server, follow the steps above on real infrastructure, and you are live. Linux or Windows, backed by a 14-day money-back guarantee.

Frequently asked questions

Are environment variables secure?
Environment variables are a configuration mechanism, not a security guarantee. Sensitive values still require controlled storage, access, rotation, and logging discipline.
Should every service use the same DATABASE_URL?
Not when separate scoped credentials are available. Give each service only the access it needs.
Should previews use production secrets?
No. Preview environments should use isolated, low-privilege credentials and should not write to production data.
Can secrets be committed in a private Git repository?
They should not be. A private repository does not replace secret lifecycle, access control, rotation, and auditing.
How should I rotate a secret?
Prefer overlapping old and new credentials, update the service, verify the new credential, then revoke the old one.

Related Articles

View all →