Skip to content

Secrets and Environment Variables

Build secrets and environment variables are treated separately. The main differences being:

  • Environment variables are saved in the final image and should not contain sensitive information. Since they are in the final image, providers can add variables that will be available to the app at runtime.
  • Secrets are never logged or saved in the build logs. They are also only available at build time and not saved to the final image.

Environment Variables

Environment variables can be set in two ways:

  1. Through step variables:
{
"steps": {
"install": {
"variables": {
"NODE_ENV": "production"
}
}
}
}
  1. Through the deploy section for runtime variables:
{
"deploy": {
"variables": {
"NODE_ENV": "production"
}
}
}

Secrets

The names of all secrets that should be used during the build are added to the top of the build plan. Each step that needs access to secrets must include them in its secrets field.

Under the hood, Railpack uses BuildKit secrets mounts to supply an exec command with the secret value as an environment variable.

By default, all secrets defined in the build plan are available to each step. You can explicitly specify which secrets a step should have access to using the secrets array. An empty array indicates that no secrets should be available to that step.

{
"secrets": ["DATABASE_URL", "API_KEY", "STRIPE_LIVE_KEY"],
"steps": {
"build": {
"secrets": ["DATABASE_URL", "API_KEY"] // Only these secrets are available to this step
}
}
}

You can also use "*" in a step’s secrets array to indicate that it should have access to all secrets defined in the build plan:

{
"secrets": ["DATABASE_URL", "API_KEY", "STRIPE_LIVE_KEY"],
"steps": {
"build": {
"secrets": ["*"] // This step has access to all secrets
}
}
}

Providing Secrets

You can add secrets when building or generating a build plan with the --env flag. The names of these variables will be added to the build plan as secrets.

CLI Build

If building with the CLI, Railpack will check that all the secrets defined in the build plan have variables.

Terminal window
railpack build --env STRIPE_LIVE_KEY=sk_live_asdf

Custom Frontend

If building with a custom frontend, you should still provide the secrets when generating the plan with --env. This adds the secrets to the build plan. You then need to pass the secrets to Docker or BuildKit with the --secret flag.

Terminal window
# Generate a build plan
railpack plan --env STRIPE_LIVE_KEY=sk_live_asdf --out test/railpack-plan.json
# Build with the custom frontend
STRIPE_LIVE_KEY=asdf123456789 docker build \
--build-arg BUILDKIT_SYNTAX="ghcr.io/railwayapp/railpack:railpack-frontend" \
-f test/railpack-plan.json \
--secret id=STRIPE_LIVE_KEY,env=STRIPE_LIVE_KEY \
--build-arg secrets-hash=asdfasdf \
examples/node-bun

For more information about running Railpack in production, see the Running Railpack in Production guide.

Layer Invalidation

By default, BuildKit will not invalidate a layer if a secret is changed. To get around this, Railpack uses a hash of the secret values and mounts this as a file in the layer. This will bust the layer cache if the secret is changed. Pass the secret hash to BuildKit with the --build-arg secrets-hash=<hash> flag.