Netlify Deploys skill for Codex

Redirects that fire and previews that stay isolated. Codex keeps Netlify build behaviour in netlify.toml with per-context environments, orders redirect rules and explains shadowing before reaching for force, and writes functions with the modern Request and Response signature. Slow work moves to background functions, periodic jobs to scheduled functions, and every change is checked on a draft deploy with curl before anyone asks for a production publish.

  • Cloud Platforms
  • $netlify-deploys
  • 184 lines
  • 2 files
  • ~1,750 tokens
  • MIT
  • Updated

Install

curl -fsSL codexskills.dev/install.sh \  | sh -s -- netlify-deploys

Installs to ~/.agents/skills/netlify-deploys/ for every project on this machine.

104-line POSIX script. No sudo, no telemetry. Read install.sh

Use it in Codex

Start a prompt with $netlify-deploys, or pick it from /skills. You can also just describe the task: Codex reads the description below and loads the playbook when your request matches.

What Codex reads before loading it

Configures and debugs Netlify sites - netlify.toml build settings and deploy contexts, _redirects and [[redirects]] rules with shadowing and force, headers, Netlify Functions (modern Request/Response handlers, background and scheduled functions), Edge Functions, Blobs and environment variables - using the netlify CLI. Use when a Netlify build fails, a redirect or SPA fallback does not fire, a function 404s or times out, deploy previews hit production data, or you are setting up draft and production deploys from CI.

Use it when

  • A Netlify build fails or differs from the local build
  • Redirects, rewrites or the SPA fallback do not behave as expected
  • You are adding Netlify Functions, background or scheduled functions
  • Deploy previews need separate environment variables from production

Use something else when

  • The site runs on Cloudflare Pages instead: use cloudflare-pages
  • You are deciding what logic should run at the edge across providers: use edge-functions

How to check the result

netlify build passes locally and a draft deploy URL returns the expected status codes, redirect targets and headers for every new rule under curl -sI.

The mistake it prevents

Expecting a redirect to override a file that exists at the same path; without force = true the static file wins.

~/.agents/skills/netlify-deploys/SKILL.md

--- name: netlify-deploys description: Configures and debugs Netlify sites - netlify.toml build settings and deploy contexts, _redirects and [[redirects]] rules with shadowing and force,… license: MIT ---

A good Netlify setup keeps all build behaviour in netlify.toml (not only in the UI), uses deploy contexts so previews never touch production secrets or data, and has redirect rules that are ordered, tested and free of accidental shadowing.

Inspect first

  1. Read AGENTS.md, netlify.toml, public/_redirects or static/_redirects, _headers, package.json and the lockfile.
  2. Check .netlify/state.json for a linked site. Linking (netlify link) and anything that reads remote env or deploys needs network and an authenticated CLI or NETLIFY_AUTH_TOKEN plus NETLIFY_SITE_ID.
  3. Identify the framework. Next.js, Astro, Remix, SvelteKit and Nuxt deploy through framework adapters that generate functions; do not hand-write functions for routes the adapter already owns.
  4. UI build settings are overridden by netlify.toml. When the two disagree, the file wins.

netlify.toml baseline

[build]
  base    = "apps/web"          # monorepo package; omit for single-package repos
  command = "npm run build"
  publish = "dist"              # relative to base

[build.environment]
  NODE_VERSION = "22"

[functions]
  directory    = "netlify/functions"
  node_bundler = "esbuild"

[context.production.environment]
  API_URL = "https://api.example.com"

[context.deploy-preview.environment]
  API_URL = "https://staging-api.example.com"

[context.branch-deploy]
  command = "npm run build:staging"

Keep secrets out of the file: set them with netlify env:set scoped to contexts, or in the UI. Values in netlify.toml are committed to git.

netlify env:list --context production
netlify env:set STRIPE_KEY sk_test_xxx --context deploy-preview branch-deploy
netlify env:set STRIPE_KEY "$PROD_VALUE" --context production --secret

Redirects and rewrites

Rules are evaluated top to bottom; the first match wins. _redirects rules are read before netlify.toml rules.

[[redirects]]
  from   = "/api/*"
  to     = "/.netlify/functions/api/:splat"
  status = 200                   # rewrite (proxy), URL stays the same

[[redirects]]
  from   = "/blog/:slug"
  to     = "/articles/:slug"
  status = 301

[[redirects]]
  from   = "/*"
  to     = "/index.html"
  status = 200                   # SPA fallback, keep last

Shadowing: by default a rule does not apply when a file exists at the requested path. That is what makes the SPA fallback safe. Add force = true only when you really want to override existing files, for example redirecting a removed page that still ships.

NeedRule
Permanent movestatus = 301
Proxy to another originto = "https://api.example.com/:splat", status = 200
Country or language routingconditions = {Country = ["de"], Language = ["de"]}
Custom 404 for a sectionfrom = "/docs/*", to = "/docs/404.html", status = 404
Gate by role (Identity)conditions = {Role = ["admin"]} with a 401 fallback rule

Functions

Modern handlers use the web Request and Response and declare their path in config:

// netlify/functions/orders.mts
import type { Config, Context } from "@netlify/functions";

export default async (req: Request, context: Context) => {
  if (req.method !== "POST") return new Response("Method not allowed", { status: 405 });
  const body = await req.json();
  const order = await createOrder(body, Netlify.env.get("DATABASE_URL"));
  return Response.json(order, { status: 201 });
};

export const config: Config = { path: "/api/orders" };
NeedUse
Request/response under the synchronous limitStandard function
Work that takes minutes (exports, emails, imports)Background function: file name ends in -background, runs up to 15 min, caller gets 202 immediately
Periodic jobScheduled function: export const config: Config = { schedule: "@hourly" } (cron syntax also works)
Per-request logic in front of every page (geo, auth gate, A/B)Edge Function in netlify/edge-functions (Deno runtime)
Small key/value or file storageNetlify Blobs: getStore("uploads") from @netlify/blobs

Synchronous functions have a short execution limit (seconds, not minutes); check the current plan docs and move anything slow to a background function plus a status endpoint. Scheduled functions run only on published production deploys.

Local loop

netlify dev                     # runs the framework dev server plus functions, redirects, env
netlify build                   # reproduces the CI build, including plugins
netlify functions:invoke orders --payload '{"sku":"A1"}'
netlify deploy --dir=dist       # draft deploy, prints a unique URL (needs network)
netlify deploy --prod --dir=dist  # production: confirm with the user first

netlify dev pulls remote env vars when the site is linked; offline it uses only local values, so missing-variable errors locally may not reproduce in the cloud.

Caching headers

[[headers]]
  for = "/assets/*"
  [headers.values]
    Cache-Control = "public, max-age=31536000, immutable"

[[headers]]
  for = "/*.html"
  [headers.values]
    Cache-Control = "public, max-age=0, must-revalidate"

For function responses, Netlify-CDN-Cache-Control controls the CDN separately from the browser. Netlify invalidates the CDN on every deploy, so hashed assets plus short HTML TTLs are the default.

Debug table

SymptomCheck
Build works locally, fails on NetlifyNODE_VERSION, base directory, lockfile present, netlify build locally
Redirect ignoredA real file shadows it, an earlier rule matches first, or the rule is in the wrong _redirects (must be in the publish dir)
Function 404Path in config, directory setting, file extension, built by adapter instead
Function timeoutMove work to background function or queue; check slow cold DB connections
Previews write to prod DBContext-scoped env vars missing for deploy-preview
Old content after deployBrowser cache from long HTML max-age, or a service worker

Verification

  • netlify build passes locally with the same Node version.
  • A draft deploy URL serves the change; curl -sI confirms redirects, status codes and headers for each new rule.
  • Functions respond under netlify dev; background functions return 202.
  • Deploy previews read preview-scoped env values.
  • Production deploys and rollbacks (publish an earlier deploy in the UI or API) only after explicit user approval.

Gotchas

  • _redirects must end up in the publish directory; frameworks often need it in public/ or static/ to be copied.
  • A 200 rewrite to an external origin is a proxy: cookies and auth headers pass through. Do not proxy to services you do not control.
  • Functions bundle only what esbuild can trace. Files read at runtime need included_files = ["data/**"] under [functions].
  • Environment variables set only in [build.environment] are available at build time, not inside functions at runtime.

What the zip contains

SKILL.md plus the interface file below. Nothing runs on install.

agents/openai.yamlgenerated from this page

Gives the Codex app a display name, a one-line description and a starter prompt for this skill.

interface:
  display_name: "Netlify Deploys"
  short_description: "Redirects that fire and previews that stay isolated"
  default_prompt: "$netlify-deploys My Netlify SPA returns 404 on refresh for nested routes, fix the redirects"

About this skill

Written and maintained by the Codex Skills editors to the same editorial standard as every skill here: a selective description, a real workflow, known pitfalls and a way to verify the work. First published , last updated . MIT licensed. Something wrong or out of date? Tell us.

esc
Just launched

Codex Skills Pro is live

79 premium skills for Codex, each with scripts, references and an evidence report that proves the result.

Bought one by one$882.21
All 79 skills$49
94% off

That's $0.62 a skill, paid once.

Get all 79 for $49Or pick single skills from $4.99 →

Secure checkout by Creem