Skip to content
PlatformJavaScript and TypeScript sites and functions

Netlify environment variables: build vs runtime

Netlify variables have scopes and deploy contexts: builds, functions and runtime each see different values. What netlify.toml can't do, and where Crunu fits.

NetlifyAt 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 with scopes, deploy contexts and write-only secret values

docs.netlify.com/build/environment-variables/overview

Crunu command
crunu run -- npm run buildRecipeCrunu has no dedicated integration here: this is the general setup.

Common pitfalls

  1. Variables declared in netlify.toml are not available to serverless functions, and they override UI values with the same key.
  2. Functions use the values that were set when the deploy was made. After changing a variable, create a new deploy.
  3. A variable reaches functions only if its scope includes Functions, and the build only if its scope includes Builds.
  4. In Lambda compatibility mode, all environment variables of a function together must fit in 4 KB.
  5. Secret scanning looks only for values Netlify stores as secrets. Values injected from elsewhere during the build aren't on its list.
On this page

On Netlify, an environment variable has a value per deploy context and, on Pro and Enterprise plans, a set of scopes that decide where it's available: the build, serverless and edge functions, runtime features like forms and signed redirects, and post-processing such as snippet injection. Values set in the Netlify UI, CLI or API can reach functions. Values declared in netlify.toml can't, and they override the UI for the same key during the build. Every deploy is pinned to the values that existed when it was created, so a change needs a new deploy. This page follows the Netlify environment variables overview, last updated October 3, 2026 and checked October 30, 2026.

Scopes: who sees a variable

ScopeWhere the value is available
Buildsthe build step, build plugins and framework and function builds
Functionsserverless functions, edge functions and on-demand builders while they run
Runtimeforms and signed proxy redirects
Post processingsnippet injection into served pages

By default a variable applies to all scopes. Narrowing scopes is the main tool for keeping a value where it belongs. A deploy key for a private package needs only Builds. A payment provider's secret key used by a checkout function needs only Functions. Nothing secret should have Post processing, and Netlify enforces that for values flagged as secret.

Deploy contexts: which value

A variable can have one value for all contexts or a different value for each: Production, Deploy Previews, Branch deploys (with per-branch overrides and wildcard prefixes such as release/*), Preview server and Local development for the Netlify CLI. A common setup gives Deploy Previews a non-production API key, so code from a pull request never runs with production credentials.

During builds, Netlify sets read-only variables you can use to tell contexts apart: CONTEXT (production, deploy-preview, branch-deploy or dev), BRANCH, COMMIT_REF, URL and DEPLOY_PRIME_URL. Only URL, SITE_NAME and SITE_ID are available to functions at runtime.

netlify.toml versus the UI

netlify.toml can declare environment variables too, and two rules about them cause most confusion:

  • They don't reach functions. The functions documentation says it twice: variables declared in netlify.toml are not available to serverless functions.
  • They override the UI during builds. A value in netlify.toml beats a variable with the same key set in the UI, CLI or API.

Netlify recommends the UI, CLI or API where possible, so sensitive values don't end up in your repository. Treat netlify.toml as a place for non-secret build settings that you're happy to review in pull requests.

Functions get deploy-time values

The functions guide is explicit: each deploy, including Deploy Previews and branch deploys, uses the environment variable values set at the time of deployment, and to apply updated values you create a new deploy. Rotating a key used by a function is therefore two steps: change the variable, then deploy. Functions read values with process.env. In Lambda compatibility mode, AWS's limit applies and all variables of a function together can't exceed 4 KB. Narrowing scopes helps stay under it, and the newer functions format removes the limit.

Secret values and scanning

Flagging a variable as Contains secret values makes it write-only. After saving, nobody can read it back through the UI, CLI or API, outside the dev context, and the flag can't be removed. Secret values must be set for explicit contexts and scopes and can't use post processing.

Secret scanning then checks your repository and build output for those values, in plain, base64 and URL-encoded form, and fails the build before publishing if it finds one. Smart detection adds a scan for things that look like secrets without any configuration.

Local development

The Local development context exists for the Netlify CLI, which gives your local dev server the values set for that context. It's handy, and it has one documented limit: variables in the Local development context can't be marked as secret. Whatever you put there is readable by anyone on the team who can see the site's variables, and it's copied onto every laptop that runs the CLI. Keep real secrets out of that context. Use throwaway development credentials, or let developers get their values another way, as described next, so a local run never needs anything stronger than a development key.

Where crunu run fits on Netlify

Netlify Functions run on Netlify's platform, and Crunu has no way to run inside them and no built-in sync into Netlify's variables. So the split is clear: function secrets stay in Netlify, scoped to Functions and flagged as secret. Crunu covers the build and local development, which is where most framework values are read anyway.

  1. Create one Crunu service token per deploy context, each granted a single environment, such as site/production for Production and site/preview for Deploy Previews.
  2. Store them as the Netlify variable CRUNU_TOKEN with a different value per context, the Builds scope only, and Contains secret values checked. Add CRUNU_SERVER, your Crunu server address, as an ordinary variable.
  3. In the build command, install crunu with the install script's --user-install mode, then run crunu run -- npm run build.
  4. Locally, run crunu run --env site/development -- npm run dev after crunu login.

Without --env, crunu run uses every environment granted to the token, which is exactly one here, so the same build command builds previews with preview values and production with production values. A pull request can't reach the production token, because Deploy Previews get the preview token.

Some honest limits. Netlify stores the tokens, so Netlify's build system can decrypt the environments they were granted, and for those environments the promise that the server can't read your values doesn't extend to Netlify. A token's lease is a window of inactivity from 1 hour to 30 days that each sign-in extends, so a site that isn't built for longer than the lease fails its next build until an owner or admin resumes the token. Scopes need a Pro or Enterprise plan. On other plans every variable applies to all scopes, so the token would also be visible to your functions. And Netlify's secret scanning knows only the values it stores. A value that crunu run passes into the build isn't on that list, so if a build writes it into a public file, only smart detection might notice. Values your framework inlines into client code, such as Vite's VITE_ variables, are public by design, so keep secrets out of those names entirely.

Frequently asked questions

Something else? Write to support@crunu.com

Are Netlify build variables available to functions at runtime?

Only variables set through the Netlify UI, CLI or API with a scope that includes Functions. Variables in netlify.toml are build-only, and a value exported inside the build command doesn't become a function variable.

Do I need to redeploy after changing a Netlify environment variable?

Yes. Each deploy uses the values that were set when it was created. Create a new deploy to apply updated values to functions and builds.

Can crunu run inside Netlify Functions?

No. Functions run on Netlify's serverless platform, where you can't run the crunu agent or wrap the function process. Function values come from Netlify's own store. Use crunu run around the build and for local development.

How do I keep a Crunu service token away from my functions?

Give the CRUNU_TOKEN variable only the Builds scope and flag it as containing secret values. Scopes are available on Pro and Enterprise plans. On other plans, a variable applies to all scopes, including functions.

Sources

Every source this page relies on, with the date we last checked it.

  1. Netlify Docs: Environment variables overview · checked October 30, 2026
  2. Netlify Docs: Build environment variables · checked October 30, 2026
  3. Netlify Docs: Environment variables and functions · checked October 30, 2026
  4. Netlify Docs: Secrets Controller · checked October 30, 2026

Keep your .env values in one place

Free during early access. Values are encrypted on your devices, each environment has its own key, and crunu run hands them to your app without writing a file.