DocupDocup
Esc

Deployment

How Docup is deployed: the Worker with the cf CLI, bindings and secrets in code, and tasks on Trigger.dev.

Docup deploys as a Cloudflare Worker plus Trigger.dev tasks. The Worker's settings live in code, in cloudflare.config.ts.

The Worker#

cloudflare.config.ts defines the Worker with defineConfig and defineWorker:

Setting Value
Name docup
Entry point ./worker.ts
Compatibility Date 2026-10-21, flag nodejs_compat
Custom domain docup.dev
Route */* in the docup.dev zone, for docs sites and custom hostnames
workers.dev Off. Preview URLs are on.
Placement Region aws:ap-south-1, near the database
Observability Logs, invocation logs, and traces persisted with head sampling rate 1, issues on
Assets htmlHandling and notFoundHandling off, with the Worker running first for everything except /_next/static/*, /*/_next/static/*, /favicon.ico, /logo.svg, and /marketing/*

A docs site needs the route in addition to the custom domain because a custom domain cannot be a wildcard. The */* route pattern catches both <address>.docup.dev subdomains and custom hostnames used for docs sites.

Bindings#

Binding Type Purpose
ASSETS Assets Static files
VERSION Version metadata The id of the deploy, used in cache keys
IMAGES Images Image optimization
ANALYTICS_ENGINE Analytics Engine dataset docup-docs-analytics One data point per docs view
SITE_FILES R2 bucket docup-assets Uploaded logos, favicons and social images
HYPERDRIVE Hyperdrive Pooled Postgres connections. In development it points at the local Docker database.
Secrets Secret Everything in Environment variables that the Worker reads

Deploying#

The Worker deploys from CI with cf deploy, which is strict: it stops if the Worker's settings in the Cloudflare dashboard differ from cloudflare.config.ts. For a manual deploy, pnpm run deploy runs vinext's Cloudflare deploy.

Never change Worker secrets, variables, bindings, routes or domains in the Cloudflare dashboard. A dashboard edit marks the Worker as edited, and the next CI deploy aborts with "Aborting the upload operation because of conflicts". Change settings in cloudflare.config.ts or with the cf CLI.

If that happens, run pnpm exec cf deploy once from a terminal and answer yes to "Would you like to continue?". That puts the Worker back to the repository's settings. The config lists the domain before the route, while Cloudflare returns the route first, so the two never match once the check runs.

Secrets#

Set each secret with the cf CLI. They are declared in the config as bindings.secret() and never stored in the repository. Tasks on Trigger.dev read their variables from the Trigger.dev dashboard instead.

Trigger.dev#

Bash
pnpm trigger:deploy

This publishes the tasks in trigger/ to your Trigger.dev project. trigger.config.ts sets the task folder, the Node runtime, a hard stop of 3,600 seconds per task and default retries of three attempts with exponential backoff. The AI tasks override the default with a single attempt, because a retry would pay for every model call again.

Database migrations#

Run pnpm db:migrate against the target database before deploying code that needs a new column. See Database.

DNS#

The wildcard route works because *.docup.dev resolves to Cloudflare. Docs sites on a new address need no DNS change.

Documentation written with Docup