Render environment variables and secret files
Render sets variables per service or through environment groups, adds secret files under /etc/secrets and passes values into Docker builds. Pitfalls and Crunu.
Part of the guide
RenderAt a glance
- Env files, highest priority first
- No .env files: values come from the process environment or the platform.
- Public prefix
- None
No names are copied into browser code by a prefix.
- Values applied
- Build and runtime
Some values are fixed at build time, the rest are read when the app runs.
- Built-in secret store
- Environment variables, environment groups and secret files
- Crunu command
crunu run --env web/production -- gunicorn app:appRecipeCrunu has no dedicated integration here: this is the general setup.
Common pitfalls
- A service's own variable beats a linked environment group, but between two groups that define the same name the winner is not guaranteed.
- Save only stores a change without deploying. The service keeps its old values until the next deploy.
- For Docker services, Render passes your variables as build arguments. Referencing a sensitive one in the Dockerfile can put it in the image.
- Secret files are copied into the root of the Docker build context. Without a .dockerignore entry they can end up in the image.
- All secret files of a service or environment group together may not exceed 1 MB.
On this page
Render gives each service environment variables that you set in the dashboard, import from a .env file, or share across services through environment groups. Values are always strings. Render also sets its own variables, such as RENDER and RENDER_SERVICE_ID, which are available at build time and at runtime unless noted. For files rather than variables, secret files appear under /etc/secrets at runtime. Changing a value doesn't touch a running service until you choose to deploy. For Docker services, Render also turns your variables into build arguments. These rules follow the Render documentation on environment variables and secrets, checked October 30, 2026.
Service variables and environment groups
| Source | Defined | Precedence |
|---|---|---|
| Service variables | on the service's Environment page | beat any linked group, guaranteed |
| Environment groups | once, linked to any number of services | between groups: not guaranteed |
| Render's defaults | set by Render for every service | not documented; don't reuse their names |
Groups are the natural place for values several services share, like a database URL used by a web service and a worker. A service can link several groups. When a service and a group define the same name, the service wins, and Render guarantees that. When two groups define the same name, Render currently uses the most recently created group and says the behavior may change without notice. Avoid overlapping names between groups instead of relying on today's order.
Render's list of default variables includes RENDER (always true), IS_PULL_REQUEST, RENDER_EXTERNAL_URL, RENDER_GIT_COMMIT and RENDER_SERVICE_ID. A few are runtime only, such as WEB_CONCURRENCY, and Node services get NODE_ENV=production at runtime only. PORT isn't set by Render. It's an optional variable you can set yourself, and the default port is 10000.
Saving and deploying
When you edit variables, Render offers three choices:
- Save, rebuild, and deploy: a new build with the new values, then a deploy.
- Save and deploy: the existing build deployed again with the new values.
- Save only: nothing is deployed, and the service uses the new values at its next deploy.
The third option is convenient for preparing changes and a common reason a rotated key "didn't work". Editing or deleting an environment group starts a deploy for every linked service that has autodeploy enabled, and linking a group or adding a secret file starts one too.
Secret files
Some programs want a file, such as a service account JSON or a TLS key. Secret files hold those:
- At runtime they're at
/etc/secrets/NAME. Non-Docker services also find them in the service's root directory. - All secret files of a service or group together are limited to 1 MB.
- For Docker builds, Render copies them into the root of the build context, as described on the Docker page. Add them to
.dockerignoreso they aren't copied into the image by a broadCOPY.
Docker builds and build arguments
For a Docker service, Render translates your environment variables into Docker build arguments available during the build, and sets them as normal environment variables at runtime. Render's own warning is direct: don't reference build arguments that contain sensitive values, such as passwords or API keys, in your Dockerfile, or those values might be included in the generated image. If a build step needs a secret, use a secret file instead.
That makes the Dockerfile the place to review. Any ARG that names a secret is a candidate for a leak, whether or not the value seems to be used.
Blueprints and .env imports
In a render.yaml Blueprint, don't commit secret values. Declare placeholder variables and fill them in the dashboard. For a quick start, Add from .env bulk-imports a file into a service. Render's docs add a reminder that's worth repeating: don't commit that .env file to source control.
A short review of a Render service
Most of the problems above are visible in a few minutes of looking, before they cause an incident:
- Overlapping names. List the variables of every linked group and look for names that appear twice. Rename or remove the duplicates rather than relying on which group was created last.
- Pending changes. If someone chose Save only, the dashboard shows values the service isn't using yet. Deploy them on purpose or revert them.
- The Dockerfile. Every
ARGshould be something you'd be comfortable seeing indocker history. Secrets belong in secret files. .dockerignore. Secret files and any local.envshould be listed, so aCOPY . .can't pick them up.- The Blueprint.
render.yamlshould contain names and placeholders only, never values.
Where crunu run fits on Render
Crunu doesn't sync into Render's variables or groups. The recommended setup keeps production values in Render and uses Crunu where people work. Starting the service under crunu run is a fallback.
Recommended: use Crunu where people work. Developers run the app locally with crunu run --env web/development -- flask --app app run, and production values are entered into Render once by whoever is allowed to. Nobody needs production values on a laptop, and Crunu's per-environment keys make sure a developer with access to development never holds the production key.
Fallback: let Render hold only a token. For a service you'd rather configure entirely from Crunu, Render stores one secret and the start command decrypts the rest.
- Create a service token limited to
web/production, without a network rule, and add it to the service asCRUNU_TOKEN. AddCRUNU_SERVER, your Crunu server address, next to it. - In the build command, install
crunuwith the install script's--user-installmode and a--bin-dirinside the project. - Set the start command to
crunu run --env web/production --restart on-change -- gunicorn app:app, using the binary from that directory. - Choose Save and deploy. Later changes in Crunu restart Gunicorn inside the running service instead of waiting for a Render deploy.
Crunu documents service tokens for CI and short-lived environments, and recommends the agent on a machine you control for long-running servers. Before you use a token this way, accept three limits:
- Render can decrypt this environment. Render stores the token and passes it to the build and the running service, and the token decrypts the environment it was granted. For this environment, the promise that the server can't read your values no longer holds: the platform holding the token can.
- An expired lease stops the service from starting. The token's lease is a window of inactivity from 1 hour to 30 days, and every sign-in extends it. If the service doesn't start for longer than the lease, for example while it's suspended, the token is refused at the next start,
crunu runexits before Gunicorn starts, and the service stays down until an owner or admin resumes the token. Choose a lease longer than the longest time the service may stay stopped. - One token per environment, with the smallest grant and no network rule. Give each service and environment its own token that reads only that environment. Don't bind it to networks: the addresses Render connects from can change, and a network rule would then lock the service out.
On Docker services the token becomes a build argument like any other variable, so never name it in an ARG. crunu run keeps CRUNU_TOKEN away from the program it starts, and a process that is already running keeps the values it has until it restarts.
Related reading
- Railway and Fly.io for comparison.
- Flask, often deployed on Render with Gunicorn.
- Secrets in Docker images and Docker Compose.
- How to share .env files with your team.
Frequently asked questions
Something else? Write to support@crunu.com
Are Render environment variables available during the build?
Render's default variables are available at build time and runtime unless noted. For Docker services, Render passes your variables to the build as build arguments and also sets them at runtime.
Where do Render secret files end up?
At runtime in /etc/secrets with their file name, and for non-Docker services also in the service's root directory. For Docker builds, Render copies them into the root of the build context.
Which value wins when a service and an environment group set the same variable?
The service's own value always wins, and Render guarantees that. When two linked groups set the same name, Render currently uses the most recently created group but says this may change without notice.
Can Crunu sync into Render environment groups?
No, there's no built-in sync. Use Crunu for development and as the place values are edited. As a fallback, start the service under crunu run with a service token so Render stores only that token, accepting that Render can then decrypt that environment.
Sources
Every source this page relies on, with the date we last checked it.
- Render Docs: Environment variables and secrets · checked October 30, 2026
- Render Docs: Default environment variables · checked October 30, 2026
- Render Docs: Docker on Render · checked October 30, 2026