GitHub Actions workflows that deploy to Netlify with netlify-cli, or running 'netlify dev' / 'netlify functions:serve' locally. Covers monorepo 'Projects detected' errors, pnpm workspace deploys, deploying pre-built directories, capturing deploy URLs, GitHub secrets setup, netlify.toml inheritance with branch deploys, isolating sub-site deploys, netlify dev with --filter, pnpm 10.x trust store errors, CLI crash workarounds. Keywords: netlify deploy, github actions netlify, netlify-cli, monorepo deploy, pnpm workspace netlify, netlify dev, netlify functions serve.
Netlify CLI for GitHub Actions
Use this skill when writing or debugging GitHub Actions workflows that deploy to Netlify using netlify-cli. This skill contains critical knowledge about common pitfalls and solutions.
Key Flags Reference
netlify deploy \
--dir=<path> # Directory to deploy (required)
--site=<site-id> # Netlify site ID
--auth=<token> # Auth token (or use NETLIFY_AUTH_TOKEN env var)
--prod # Deploy to production (default: draft)
--build # Opt-in to running build before deploy (deploy does NOT build by default)
--filter=<package> # Select package in monorepo - CRITICAL for pnpm workspaces
--functions=<folder> # Override functions directory (useful to skip functions with empty dir)
--alias=<name> # Custom subdomain for draft deploys
--message=<msg> # Deployment message
--json # Output as JSON (for programmatic URL extraction)
IMPORTANT: There is NO --no-build flag in netlify-cli@19+. netlify deploy does NOT build by default. Use --build only if you want to opt-in to building.
Critical: Monorepo "Projects Detected" Error
When deploying from a pnpm workspace or monorepo, you will encounter:
Error: Projects detected: package-a, package-b. Configure the project you want to work with and try again.
Solution
Use the --filter flag to select the target package:
--filter=<package-name>: Selects the package (use the name from package.json)
netlify deploy does NOT build by default, so no extra flag is needed to skip building
Critical: netlify.toml Inheritance Problem
The CLI always reads netlify.toml from the project root, regardless of the --dir flag. This means:
Redirects defined in the root netlify.toml apply to ALL deploys (including branch/alias deploys)
Functions from the root config are bundled into every deploy
Circular proxy: If root netlify.toml has a redirect like /doc/* -> https://doc--mysite.netlify.app/doc/:splat with force = true, the branch deploy will proxy to itself, causing 404s
Solution: Deploy from an Isolated Directory
To prevent the root netlify.toml from affecting a sub-site deploy, deploy from a separate directory with its own minimal netlify.toml:
working-directory: deploy-output makes the CLI find the local netlify.toml instead of the root one
--functions=.empty-functions overrides the root's functions directory to avoid bundling errors
The local netlify.toml has no redirects, so no circular proxy issues
--filter is not needed when deploying from an isolated directory (no monorepo detection)
Critical: basePath / baseUrl Wrapping for Proxied Deploys
When a sub-site is proxied from the main site under a path prefix (e.g., mysite.com/doc/ -> doc--mysite.netlify.app/doc/), the build output must be nested in a matching subdirectory.
Problem: netlify deploy --dir=doc/build deploys files at root /. But if the framework (e.g., Docusaurus with baseUrl: '/doc/') generates asset references like /doc/assets/main.js, they will 404 because the actual file is at /assets/main.js.
Solution: Wrap the build output in the correct subdirectory before deploying:
Solution: Add --filter=<package-name> flag to netlify deploy
Error: "Projects detected" with netlify link
Cause: netlify link does NOT support --filter flag and fails in monorepos
Solution: Don't use netlify link in monorepos. It's unnecessary when using --site flag with netlify deploy. The --site flag directly specifies the target site, making explicit linking redundant.
Error: "unknown option '--no-build'"
Cause: --no-build does not exist in netlify-cli@19+
Solution: Remove the flag. netlify deploy does NOT build by default. Use --build only when you want to opt-in to building.
Error: "Could not resolve @netlify/blobs" (or other function bundling errors)
Cause: The CLI picks up functions from the root netlify.toml config, even when deploying a sub-site that doesn't need functions
Solution: Use --functions=<empty-dir> to override. Create an empty directory and point to it:
Cause: Root netlify.toml has a redirect like /doc/* -> https://doc--mysite.netlify.app/doc/:splat with force = true. On the branch deploy itself, this redirect proxies to itself.
Solution: Deploy from an isolated directory with its own netlify.toml that has no redirects. Use working-directory in the GitHub Actions step so the CLI finds the local config instead of the root one.
Error: "Build directory not found"
Cause: Wrong --dir path or build artifacts not downloaded
Solution: Verify path and ensure artifacts are downloaded in CI
Error: "Invalid character in header"
Cause: Whitespace in auth token
Solution: Trim the token: export NETLIFY_AUTH_TOKEN=$(echo "$TOKEN" | tr -d '[:space:]')
Setup Requirements
GitHub Secrets Needed
NETLIFY_SITE_ID - From Site settings -> General -> Site details -> API ID
NETLIFY_AUTH_TOKEN - From User settings -> Applications -> Personal access tokens
Disable Netlify Auto-Build
When using GitHub Actions for deployment, disable Netlify's built-in CI:
Note: This action may not handle monorepo scenarios well - use CLI directly for those cases.
Local Development with netlify dev
Basic Usage (Monorepo)
In a monorepo, netlify dev requires --filter to select the project. Without it, the CLI enters an interactive project selection prompt that blocks non-interactive environments:
# This works - selects the correct package
netlify dev --functions=netlify/functions --offline --filter my-package
# This gets stuck at interactive prompt
netlify dev --functions=netlify/functions --offline
A typical package.json script:
{"netlify:dev":"PNPM_DISABLE_TRUST_STORE=true pnpm --package=netlify-cli dlx netlify dev --functions=netlify/functions --offline --filter my-package"}
What netlify dev Does
Starts your framework's dev server (e.g., Next.js on port 34434)
ERR_PNPM_TRUST_DOWNGRADE High-risk trust downgrade for "@netlify/edge-bundler@14.9.5"
The PNPM_DISABLE_TRUST_STORE=true env var may not work with pnpm dlx even though pnpm config list shows trust-store=false. This is a pnpm 10.x behavior where dlx creates its own install context.
Workarounds:
Install netlify-cli globally instead of using pnpm dlx:
npm install -g netlify-cli
netlify dev --functions=netlify/functions --offline --filter my-package
Use npx (if the global install exists):
npx netlify-cli dev --functions=netlify/functions --offline --filter my-package
netlify dev Crash Workaround
netlify dev may crash with "Netlify CLI has terminated unexpectedly" after the proxy starts (observed in v23.14.0+). The proxy on port 8888 starts successfully but terminates immediately.
Workaround: Run functions separately
Use netlify functions:serve to run just the functions server on port 9999, then run your framework dev server separately:
# Terminal 1: Start functions server (port 9999)
netlify functions:serve --functions=netlify/functions --offline --filter my-package
# Terminal 2: Start Next.js dev server (port 34434)
pnpm dev
Limitation: Without the netlify dev proxy, API rewrites from netlify.toml (e.g., /api/products → /.netlify/functions/get-products) won't work. The functions are accessible directly at:
For frameworks with output: 'export' (static site generation), Next.js rewrites() cannot be used. In this case, test the functions directly at the port 9999 URL.