pyssg is pre-1.0 and under active development - APIs, config, and themes may change.
pyssg.deploy.cloudflare

2 min read

pyssg.deploy.cloudflare

Cloudflare Pages deploy target (pyssg deploy cloudflare).

Publishes the built site with Cloudflare Pages' Direct Upload protocol -- the same content-addressed flow Wrangler uses. Each file is hashed, the API is asked which hashes it does not already have, only the missing files are uploaded (deduplicated across the site and across previous deploys), and finally a deployment is created from a manifest mapping every served path to its hash.

The asset endpoints (/pages/assets/*) are not part of Cloudflare's public, documented REST surface; they are the routes the official tooling uses and may change without notice. The hash is BLAKE3 of base64(content) + extension truncated to 32 hex characters, matching Wrangler exactly so uploads dedupe against deployments made by other tools.

This target uses HTTP, so it needs the optional pyssg[deploy] extra (httpx for the client, blake3 for the hash). Both are imported lazily so that merely importing this module -- which the CLI does to populate the deploy registry -- never requires the extra; only an actual deploy does.

Configuration (under Config.deploy["cloudflare"]):

  • account_id (required) -- Cloudflare account id that owns the project.
  • project (required) -- Pages project name.
  • branch (optional) -- deployment branch; when it equals the project's production branch Cloudflare publishes to production, otherwise a preview. Omitted by default (Cloudflare uses the project's production branch).
  • concurrency (optional, default 10) -- parallel upload batches.

Authentication: the CLOUDFLARE_API_TOKEN environment variable, scoped Account > Cloudflare Pages > Edit. The token is read from the environment, never from config.

class CloudflareTarget

Deploy to Cloudflare Pages via the Direct Upload protocol.

Stateless with respect to the pipeline. The test seams (transport, sleep, retry/backoff knobs) let the upload flow run against an httpx MockTransport with no real network or wall-clock delay; production uses the defaults.

CloudflareTarget.__init__(self, *, transport: httpx.AsyncBaseTransport | None = None, sleep: Callable[[float], Awaitable[None]] | None = None, max_retries: int = 4, backoff_base: float = 0.5) -> None

CloudflareTarget.required_env(self) -> list[str]

The Pages API token; everything else comes from config.

CloudflareTarget.required_config_keys(self) -> list[str]

Account and project identify which Pages project to deploy to.

async CloudflareTarget.deploy(self, ctx: DeployContext) -> DeployResult

Upload missing assets and create a Cloudflare Pages deployment.

Returns the deployment id and its URL. Raises :class:DeployError on a missing extra, an API error, or a malformed response.