Reference for netlify.toml configuration and site environment variables. Use when configuring build settings, redirects, rewrites, headers, deploy contexts, the `[dev]` block that controls `netlify dev` (command, port, targetPort, framework), or any site-level configuration โ
Installs just this skill. Get the whole plugin for auto-invocation.
โก How it fires
How this skill gets triggered: by you, by Claude, or both.
Fires itselfClaude auto-loads it when your prompt matches the work.
You can call itInvoke it directly when you want it.
Slash command/netlify-config
๐๏ธ Context preview
The summary Claude sees to decide when to auto-load this skill.
Reference for netlify.toml configuration and site environment variables. Use when configuring build settings, redirects, rewrites, headers, deploy contexts, the `[dev]` block that controls `netlify dev` (command, port, targetPort, framework), or any site-level configuration โ
๐ Stats
Stars27
Forks8
LanguageTypeScript
LicenseMIT
๐ฆ Ships with netlify-skills
</> SKILL.md
netlify-config.SKILL.md
---name: netlify-config
description: Reference for netlify.toml configuration and site environment variables. Use when configuring build settings, redirects, rewrites, headers, deploy contexts, the `[dev]` block that controls `netlify dev` (command, port, targetPort, framework), or any site-level configuration โ and when managing environment variables or secrets with the Netlify CLI, including scoping values to specific deploy contexts. Covers the complete netlify.toml syntax including redirects with splats/conditions, headers, deploy contexts, functions config, edge functions config, and the `[dev]` block (including when `framework` must be `"#custom"` โ required when both a custom `command` and `targetPort` are set).
---# Netlify Configuration (netlify.toml)
Place `netlify.toml` at the repository root. In a monorepo, Netlify searches for the config and uses the **first** one it finds: the package directory (the subdirectory containing the site), then the base directory, then the repository root โ so put a site-specific `netlify.toml` in the package directory to take precedence over root-level config (see the **netlify-deploy** skill's monorepo notes).
**`netlify.toml` takes precedence over the Netlify UI.** When the same property (build command, publish directory, an environment variable, a redirect, a header) is configured in both places, the value in `netlify.toml` wins and silently overrides the corresponding Netlify UI setting โ the dashboard field still shows its old value but is inert. Once a `netlify.toml` is present, treat it as the source of truth and change settings there, not in the UI.
## Build Settings
```toml
[build]
base = "project/" # Base directory (default: root)
status = 301 # 301 (default), 302, 200 (rewrite), 404
# SPA catch-all
[[redirects]]
from = "/*"
to = "/index.html"
status = 200
# Splat (wildcard)
[[redirects]]
from = "/blog/*"
to = "/news/:splat"
# Path parameters
[[redirects]]
from = "/users/:id"
to = "/api/users/:id"
status = 200
# Force (override existing files)
[[redirects]]
from = "/app/*"
to = "/index.html"
status = 200
force = true
# Proxy to external service
[[redirects]]
from = "/api/*"
to = "https://api.example.com/:splat"
status = 200
[redirects.headers]
X-Custom = "value"
# Country/language conditions
[[redirects]]
from = "/*"
to = "/fr/:splat"
status = 200
conditions = { Country = ["FR"], Language = ["fr"] }
```
**Rule order matters** โ Netlify processes the first matching rule. Place specific rules before general ones.
Redirect rules can also live in a plain-text `_redirects` file in the publish directory. If both a `_redirects` file and `[[redirects]]` in `netlify.toml` exist, the `_redirects` file rules are processed **first**, then the `netlify.toml` rules, reading top to bottom โ and the first matching rule wins. The same ordering applies to a `_headers` file versus `[[headers]]`. Because a `_redirects` rule can silently shadow a `netlify.toml` rule for the same path, keep overlapping rules in a single source.
Headers apply only to files served from Netlify's CDN (not to function or edge function responses โ set those in code).
## Deploy Contexts
Override settings per deploy context:
```toml
[context.production]
command = "npm run build"
environment = { NODE_ENV = "production" }
[context.deploy-preview]
command = "npm run build:preview"
[context.branch-deploy]
command = "npm run build:staging"
[context.dev]
environment = { NODE_ENV = "development" }
# Specific branch
[context."staging"]
command = "npm run build:staging"
```
**`[[redirects]]` and `[[headers]]` are global โ they cannot be scoped to a deploy context.** Context tables like `[context.production]` work for keys such as `[build]`, `[build.environment]`, and `[[plugins]]`, but redirect and header rules apply to every context no matter where you place them in the file; there is no `[context.production.redirects]` or context-nested `[[redirects]]`. For context-specific redirects or headers, use the per-deploy escape hatch: generate a `_redirects` or `_headers` file during that context's build (those files ship per deploy), or gate the behavior on a runtime signal in an edge function.
## Environment Variables
```toml
[build.environment]
NODE_VERSION = "20"
[context.production.environment]
API_URL = "https://api.prod.com"
[context.deploy-preview.environment]
API_URL = "https://api.staging.com"
```
**Do not put secrets in netlify.toml** (it's committed to source control). Use the Netlify UI or CLI for sensitive values โ see CLI Management below.
**Variables declared in `netlify.toml` are build-scoped only.** Values under `[build.environment]` or `[context.*.environment]` are available to the build (and snippet injection) but are **not** injected into the Functions or Edge Functions runtime โ reading them with `Netlify.env.get("VAR")` or `process.env.VAR` inside a function returns `undefined`. To make a variable available at function runtime, set it in the Netlify UI or with `netlify env:set` (those are available to both builds and runtime), not in `netlify.toml`.
### CLI Management
```bash
# Set
netlify env:set API_KEY "value"
netlify env:set API_KEY "value" --secret # Hidden from logs
netlify env:set API_KEY "value" --context production # Context-specific
# Get
netlify env:get API_KEY
# List
netlify env:list
netlify env:list --plain > .env # Local snapshot only โ keep .env gitignored, never commit it
# Import from file
netlify env:import .env
# Delete
netlify env:unset API_KEY
```
**Never put secrets in client-prefixed variables** (`VITE_`, `PUBLIC_`, `NEXT_PUBLIC_`, `NUXT_PUBLIC_`) โ these are inlined into the client bundle and exposed to the browser. `--secret` only hides a value from logs and the UI; it does not protect a client-prefixed variable.
### Context Scoping
Variables set via the CLI can also be scoped to deploy contexts:
```bash
netlify env:set API_URL "https://api.prod.com" --context production
This is the CLI equivalent of the `[context.*.environment]` tables above, but the resulting variables are available at both build and runtime (unlike `netlify.toml`-declared ones).
When reading these variables in server code, prefer `Netlify.env.get("VAR")`. `process.env.VAR` also works inside Functions, but Edge Functions expose only `Netlify.env.get` โ the portable form keeps the same code working in both runtimes.
For the client-side rules (`VITE_`/`PUBLIC_` prefixes and framework specifics), see the **netlify-frameworks** skill; for function-side details, see **netlify-functions**.
## Functions Configuration
```toml
[functions]
directory = "netlify/functions" # Default
node_bundler = "esbuild"
# Scheduled function
[functions."cleanup"]
schedule = "@daily"
```
Use the single-table `[functions]` form for global settings and `[functions."name-or-glob"]` for per-function overrides. There is **no** `[[functions]]` array-of-tables and no path-based function routing table in `netlify.toml` โ functions are routed by file (served at `/.netlify/functions/{name}`) or by an in-code `path`/`config` export, not by config.
## Edge Functions Configuration
```toml
[[edge_functions]]
path = "/admin/*"
function = "auth"
excludedPath = "/admin/public/*" # Carve exceptions out of `path` (string or array of globs)
**If you set both a custom `command` and a `targetPort`, `framework` must be `"#custom"`.** With `framework = "#auto"` (the default) Netlify Dev runs its own detector and ignores your custom `command`; `"#custom"` tells it to run your `command` as the app server and connect to `targetPort`. Setting `command` + `targetPort` while leaving `framework` at `#auto` (or omitting it) is a silent misconfiguration.
## Plugins
```toml
[[plugins]]
package = "@netlify/plugin-lighthouse"
[plugins.inputs]
audits = ["performance", "accessibility"]
```
## Image CDN
```toml
[images]
remote_images = ["https://example\\.com/.*"]
```
See the **netlify-image-cdn** skill for full Image CDN usage.