A deploy button is one HTTP request

Static sites need rebuilding when content changes. It is tempting to believe your CMS provides that capability. It almost certainly does not — it provides a button, and the button posts to a URL.

Cover for A deploy button is one HTTP request
Updated: Aug 4, 2026
TL;DR

The deploy capability lives in your host’s hook URL, not in your CMS. Anything that can send a POST can replace the admin panel button: a cron job, a webhook, a bookmark.

A static site has to be rebuilt when its content changes. If the content lives in a CMS, the natural place for that trigger is the CMS admin panel, and so that is where it usually ends up.

Then you consider moving the content somewhere else, and the button feels like a reason not to.

What the button actually is

Here is the whole thing, more or less:

export async function POST() {
  const { user } = await payload.auth({ headers: await getHeaders() })

  if (!user) {
    return Response.json({ error: 'Unauthorized' }, { status: 401 })
  }

  const response = await fetch(process.env.FRONTEND_DEPLOY_HOOK!, { method: 'POST' })

  return response.ok
    ? Response.json({ success: true })
    : Response.json({ error: 'Deploy hook failed' }, { status: response.status })
}

An auth check, and a POST to a URL your host gave you. That is the entire deploy system. The CMS contributes two things: somewhere to click, and a guard on who may click it.

Four replacements

  1. A scheduled build with a change check. Cron asks the content source for the newest edit timestamp and skips the build if nothing moved. Nothing to remember, nothing to press.
  2. A webhook from wherever the content lives. Most content tools can fire an HTTP request when a status property changes. That is the same button, closer to the writing.
  3. A bookmark. Deploy hook URLs are unguessable and the blast radius of a leak is a wasted build. A bookmarklet is a legitimate answer.
  4. A workflow_dispatch job. A run button in the repository, with real authentication behind it, if you would rather the trigger live next to the code.

If a capability is one HTTP request, it is not a reason to keep a system. It is a reason to notice you were keeping the system for something else.

The part that is genuinely harder

Losing the button costs nothing. Losing save-time validation is the real question, and it deserves a straight answer rather than a reassuring one.

A CMS rejects one bad document at the moment it is saved, next to the field that is wrong, in language the person typing can act on. A build rejects the whole queue, in a log, minutes later, and blocks everyone else’s finished work until someone reads it.

Rejected at saveRejected at build
Who sees itthe authorwhoever reads logs
What it blocksone documentevery queued document
Feedback delayimmediateone build

For a single author who triggers their own builds, all three rows collapse to nothing: you broke it, you read the log, thirty seconds apart. For five authors, two of whom do not have repository access, that table is the entire argument for keeping a CMS.

The actual decision

Not can we replace the button — you can, four ways, this afternoon. It is whether the number of people writing, times their distance from the build, is large enough that catching mistakes at save time is worth an admin panel, a database and a deployment to maintain.

Answer that honestly and the button never enters into it.

Related Posts

The Starter

Lorem ipsum dolor sit amet, consectetur adipiscing elit. Lectus interdum facilisis odio scelerisque vel neque.

Copyright 2026The Starter. All Rights Reserved