netlify-config

Configure Netlify projects via netlify.toml and the _headers/_redirects files — covering build settings and deploy contexts alongside environment variables/scopes and the Secrets Controller plus redirect/rewrite/proxy and custom-header rules. Use when setting a build command or publish directory, ad

By netlify · 2,391 installs

npx skills add netlify/context-and-tools --skill netlify-config

Source repository · Upstream listing

Netlify configuration netlify.toml lives at the repo root (or set base /package directory for monorepos). Settings in netlify.toml override the Netlify UI on conflict. headers and redirects are extensionless plain text files in the publish directory , processed before netlify.toml rules. Footguns (read first) Env vars in netlify.toml are NOT available to functions or edge functions at runtime — reading them there returns undefined . Vars declared in netlify.toml only get the Builds and Post processing scopes. Set runtime vars in the UI or with netlify env:set . Never put secrets in client prefixed vars ( VITE , NEXT PUBLIC , PUBLIC , …) — they are inlined into the client bundle. secret does not protect them. .env is not read by the Netlify build system — import variables into Netlify first ( netlify env:import ). The CLI reads .env only for local builds. Direct env injection into netlify.toml ( key = "$VAR" ) is unsupported — except signed proxy redirects. Use a build plugin or sed in the build command. [[redirects]] and [[headers]] are global — NOT context aware, cannot be scoped to branches/contexts. Workaround: per context build command copies a custom file into the publish directory. Proxy rewrites time out at 26 seconds. HTTP 307 is unsupported — use 302 . netlify.toml — core structure Context precedence (least → most specific): UI settings < base context aware key < [context.production deploy preview branch deploy dev] < [context.branchname] . Only [build] and [[plugins]] are context aware. All paths are absolute relative to the base directory (root / default). Config file search order: package directory → base directory → root. Functions config esbuild = smaller/faster artifacts; TypeScript functions always use esbuild . external node modules applies only with esbuild . included files : wildcard, ! excludes; paths absolute to base. Environment variables Set runtime/scoped vars via CLI/UI/API (not netlify.toml ): Keep any .env snapshot gitignored — never commit it. Types: site vars (one site) vs shared vars (whole team; Pro/Enterprise; Team Owners only). Scopes (Pro/Enterprise; default = all): Builds , Functions (also Edge Functions + On demand Builders), Runtime (forms, signed proxy redirects), Post processing (snippet injection). Vars from netlify.toml are locked to Builds + Post processing . Scope precedence is independent per scope: a site variable scoped only to Builds does NOT shadow a shared variable for the Functions scope — the shared value still applies there. Site beats shared only within the scopes the site variable actually carries. Deploy context values: Production , Deploy Previews , Branch deploys (override per branch with a Branch value, wildcard suffix release/ ), Preview server , Local development . Overrides: netlify.toml vars override same key UI/CLI/API vars. Site var beats shared var per its scopes/contexts. Limits: keys ≤ 255 chars, alphanumeric + underscore, first char a letter ( KEY1 ok; 1KEY / KEY1 invalid). Values ≤ 5,000 chars (functions within AWS limits). Reserved read only names can't be overridden. Build variables Settable in netlify.toml [build.environment] : NODE VERSION , NODE ENV , NPM VERSION , NPM FLAGS , NPM TOKEN , YARN VERSION , PNPM FLAGS , BUN VERSION , RUBY VERSION , PHP VERSION , PYTHON VERSION , GO VERSION , HUGO VERSION , NETLIFY USE YARN , CI , etc. Set in UI/CLI only (NOT netlify.toml , which is read after clone): AWS LAMBDA JS RUNTIME , GIT LFS ENABLED , GIT LFS FETCH INCLUDE , NETLIFY BUILD DEBUG . Read only build metadata (examples): NETLIFY , BUILD ID , CONTEXT ( production / deploy preview / branch deploy / dev ), BRANCH , HEAD , COMMIT REF , CACHED COMMIT REF , PULL REQUEST , REVIEW ID , URL , DEPLOY URL , DEPLOY PRIME URL , DEPLOY ID , SITE NAME , SITE ID , ACCOUNT ID . Access: Bash $VAR NAME in build/ignore commands; process.env.VAR NAME in Node scripts and plugins. Scope must include Builds . Inject env values into headers/redirects Substitution only reaches [[headers]] / [[redirects]] (read after build); NOT available to build plugins. Alternatively mutate netlifyConfig in a local build plugin. Redirects & rewrites redirects (one rule per line) or [[redirects]] . Rules process top down; first match wins. redirects /file rules run before netlify.toml . Force/shadow: you can't shadow an existing URL by default — append ! in redirects or force = true in toml. Splats ( ) only at the end of a path segment ( /jobs/ .html won't work). Can't exclude a path from a splat — order a more specific rule first. Query: id=:id matches URLs with only id and no other params. List optional param variants most general last. Trailing slash: URLs are normalized before rules run; you cannot add/remove a trailing slash via a redirect (infinite loop). Pretty URLs (on by default) handle standardization. Country/Language conditions: no spaces ( Country=au,nz ). Country = ISO 3166 1 alpha 2; Language = browser/locale codes, matches the FIRST Accept Language entry. nf country / nf lang cookies override. Domain redirects: HTTP and HTTPS need separate rules unless forcing SSL; the domain must be assigned to the site. Role based redirects with external auth: Enterprise only. HTTP 307 unsupported → use 302 . 10,000+ redirects: favor wildcards/placeholders; serialization across redirects + netlify.toml can fail the deploy if too large — consider Edge Functions. Rewrites & proxies (status 200) No cross team rewrites between Netlify sites. Infinite loop rules (from == to) are ignored. Internal rewrites limited to one hop. Proxy timeout 26s — use async for longer. Rewrites break relative path assets — use absolute paths or <base . Proxy to another Netlify site: use its .netlify.app subdomain. Rewrites into a separate password protected site are not allowed. Signed proxy redirects ( netlify.toml only) Must be in netlify.toml ; env var scope must include Runtime ; not supported proxying Netlify→Netlify. Netlify sends the JWS as HMAC HS256 in the x nf sign header. (This is the one place $VAR style env injection is allowed.) Custom headers Headers apply only to files Netlify serves from its own store — proxied content, functions, and edge/SSR pages must return their own headers. Reserved header names Netlify controls (ignored if you set them): Content Length , Content Encoding , Location (use redirects), Set Cookie (may be overridden), Server , Date , Age , Connection , Transfer Encoding , etc. Basic Auth headers: Pro/Enterprise. Cross subdomain cookies impossible on .netlify.app (Public Suffix List) — needs a custom domain. Global only; per branch via the build command copy workaround. Secrets Controller Mark a var secret via secret (CLI), is secret: true (API), or the UI. Enforced, non customizable policy: Values are write only — no readable version after setting; the flag can't be removed to reveal a value. Must be set to explicit deploy contexts and scopes; cannot have the post processing scope. Only code on Netlify reads unmasked values; outside code gets masked. The dev context value is unmasked and exempt. Secret scanning (smart detection: Personal/Pro/Enterprise) runs on the next build after marking a var secret. Resolve a detection by removing the value at the location in the deploy log, then redeploy. Safelist false positives via SECRETS SCAN SMART DETECTION OMIT VALUES (comma separated), then redeploy. Sensitive variable policy (public repos only): untrusted deploys (unrecognized authors) default to Require approval ; alternatives are Deploy without sensitive variables or Deploy without restrictions . Not available for GitHub Enterprise Server / GitLab self managed (treated as private). Ignore builds Exit 0 = no changes, build stops ; exit 1 = changed, build continues. Runs from base directory; uses fixed Node.js 18 (not customizable); site package.json deps unavailable. Referenced file paths must start with ./ . Won't cancel a build triggered by a build hook, regardless of exit code. Node.js variant: JavaScript SPAs Hashed/code split filenames + atomic deploys can break asset refs ( Uncaught SyntaxError: Unexpected token ) — disable hashed filenames, use permalinks, or a service worker. Monorepos Recommended: set the site's subdirectory as the package directory (keep netlify.toml there), leave base directory at repo root / , declare deps at the subdirectory level. Package directory is UI only (Build settings Configure) — it cannot be set in netlify.toml . Base directory can be set in root level netlify.toml ( [build] base ) and overrides the UI. Use absolute paths relative to base: base /frontend + plugin at /frontend/packages/my app/plugins → specify /packages/my app/plugins/... . Build only on subdirectory changes with an ignore command. CLI: filter <site . Netlify caches all node modules regardless of where deps are declared. Plugins, extensions, dev, templates [dev] has no environment property — set local env vars in [context.dev.environment] instead. framework values: auto (default), static , custom . For Deploy to Netlify buttons use [template] / [template.environment] . Post processing pretty URLs: <! TOML syntax reference: https://toml.io/en/ · Netlify config docs: https://docs.netlify.com/build/configure builds/file based configuration.md <! system: agent context/config/system.md — human owned, merged by ctx gen; edit system.md, not this section Netlify house rules (config) These are org conventions, not docs facts — merged into the rendered skill by ctx gen and never generated. Owned by the skills maintainer. 1. Env vars set in netlify.toml are NOT available to functions or edge functions at runtime — reading them there returns undefined . Set runtime vars in the UI or with netlify env:set , not netlify.toml . 2. Never put secrets in client prefixed env vars ( VITE , NEXT PUBLIC , PUBLIC , ...) — they are inlined into the client bundle; secret does not protect them. 3. When snapshotting env vars locally ( netlify env:list plain .env ), keep .env gitignored — never commit it. 4. State env var scope interaction explicitly: a site variable scoped to Builds does not shadow the shared variable for other scopes — precedence resolves independently per scope (site beats shared only within the scopes the site variable actually carries).