Skip to content

Deploy Hooks

By default, Workers Builds triggers a build when you push a commit to your connected Git repository. Deploy Hooks provide another way to trigger a build. Each hook is a unique URL that triggers a manual build for one branch when it receives an HTTP POST request. Use Deploy Hooks to connect Workers Builds with workflows such as:

  • Rebuild automatically when content changes in a headless CMS
  • Build on a schedule using an external cron service
  • Trigger deployments from custom CI/CD pipelines based on specific conditions

Create a Deploy Hook

Before creating a Deploy Hook, ensure your Worker is connected to a Git repository.

  1. Go to Workers & Pages and select your Worker.

    Go to Workers & Pages
  2. Go to Settings > Builds > Deploy Hooks.

  3. Enter a name and select the branch to build.

  4. Select Create and copy the generated URL.

Trigger a Deploy Hook

Send an HTTP POST request to your Deploy Hook URL to start a build:

Terminal window
curl -X POST "https://api.cloudflare.com/client/v4/workers/builds/deploy_hooks/<DEPLOY_HOOK_ID>"

No Authorization header is needed. The unique identifier embedded in the URL acts as the authentication credential.

Example response:

{
"success": true,
"errors": [],
"messages": [],
"result": {
"build_uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"branch": "main",
"worker": "my-worker"
}
}

The build_uuid in the response can be used to monitor build status and retrieve logs.

Verify the build

After you trigger a Deploy Hook, you can verify it from the dashboard:

  • In the Deploy Hooks list, the hook shows when it was last triggered.
  • In your Worker's build history, the Triggered by column identifies builds started by a Deploy Hook using the hook name and a deploy hook label.

If you need to inspect these builds programmatically, use List builds for a Worker in the Builds API reference. Hook-triggered builds are recorded with build_trigger_source: "deploy_hook".

CMS integration

Most headless CMS platforms support webhooks that call your Deploy Hook URL when content changes. The general setup is the same across platforms:

  1. Find the webhooks or integrations settings in your CMS.
  2. Create a new webhook and paste your Deploy Hook URL as the target URL.
  3. Select which events should trigger the webhook (for example, publish, unpublish, or update).

Refer to your CMS documentation for platform-specific instructions. Popular platforms with webhook support include Contentful, Sanity, Strapi, Storyblok, DatoCMS, and Prismic.

Idempotency

If the same Deploy Hook is triggered again before the previous build has fully started, Workers Builds does not create a duplicate build. Instead, it returns the build that is already in progress.

If an external system sends the same Deploy Hook twice in quick succession:

  1. The first request creates a build.
  2. If a second request arrives while that build is still queued or initializing, no second build is created.
  3. Instead, the response returns the existing build_uuid and sets already_exists to true.

Example response when an existing pending build is returned:

{
"success": true,
"errors": [],
"messages": [],
"result": {
"build_uuid": "a1b2c3d4-e5f6-7890-abcd-ef1234567890",
"status": "queued",
"created_on": "2026-01-21T18:50:00Z",
"already_exists": true
}
}

Once the earlier build moves past initializing, a later POST creates a new build as normal. This makes Deploy Hooks safe to use with systems that retry webhooks or emit bursts of content-update events.

Examples

Deploy from a Slack slash command

A Worker that receives a /deploy command from Slack and triggers a build:

JavaScript
export default {
async fetch(request, env) {
const body = await request.formData();
const command = body.get("command");
const token = body.get("token");
if (token !== env.SLACK_VERIFICATION_TOKEN) {
return new Response("Unauthorized", { status: 401 });
}
if (command === "/deploy") {
const res = await fetch(env.DEPLOY_HOOK_URL, { method: "POST" });
const { result } = await res.json();
return new Response(`Build started: ${result.build_uuid}`);
}
return new Response("Unknown command", { status: 400 });
},
};

Rebuild on a schedule

A Worker with a Cron Trigger that rebuilds every hour:

JavaScript
export default {
async scheduled(event, env) {
await fetch(env.DEPLOY_HOOK_URL, { method: "POST" });
},
};

Security considerations

  • Store Deploy Hook URLs in environment variables or a secrets manager, never in source code or public configuration files.
  • Restrict access to the URL to only the systems that need it.
  • If a URL is compromised or you suspect unauthorized use, delete the Deploy Hook immediately and create a new one. The old URL stops working as soon as it is deleted.

Using the Builds API for authenticated triggers

If your external system supports custom headers, you can call the manual build endpoint with an API token in the Authorization header instead. This gives you token-based authentication and the ability to choose the branch per request. For a step-by-step walkthrough, see Trigger a manual build.

Limits

Deploy Hooks are rate limited to 10 builds per minute per Worker and 100 builds per minute per account. For all Workers Builds limits, see Limits & pricing.