Ship

Deployment

npx goribu deploy builds the app, resolves Cloudflare resources, runs any pending production migrations and ships to Workers, all in one command, from your app root.

npx goribu deploy

The first deploy publishes to a *.workers.dev subdomain, and Wrangler prints the live URL when it finishes:

Resolving Cloudflare resources…
Writing deploy config…
Running migrations against production D1…
Deploying…
Uploaded my-app (3.42 sec)
  https://my-app.my-account.workers.dev

Done. Your app is now live at the URL shown above.

The build prerenders every route that needs no request data, so those are served by Cloudflare Static Assets without invoking the Worker. And migrations run before the new Worker ships: if one fails, the deploy stops and the old Worker keeps serving the old code. New code only goes live when the schema is ready for it.

That is the whole happy path. Everything below is for when you need more.

Going deeper

Custom domains

Set up a Custom Domain from the Cloudflare dashboard: Workers & Pages → your worker → Settings → Domains & Routes → Add → Custom Domain. Cloudflare handles DNS, SSL and routing; there is nothing to add to goribu.config.js. This is what most apps need and it works out of the box. (Use the route config option only if you want a Cloudflare route pattern instead, see Configuration.)

Secrets and environment

If .env.production exists, goribu deploy runs wrangler deploy --secrets-file=.env.production, so its values become Cloudflare secrets atomically with the new Worker version. Secrets already on Cloudflare that are not in the file are preserved. Without the file the deploy runs plain and prints No .env.production found. Using existing platform secrets., so you can manage secrets with wrangler secret put instead. See Configuration for the full env model.

Migrations

For D1 there is nothing to configure as Goribu reads database.name, resolves it to a UUID and creates the database on first deploy if it is missing.

For Postgres you must supply a connection string with DDL permission, since the Hyperdrive runtime credentials usually lack CREATE/ALTER:

# As an env var (recommended for CI)
POSTGRES_URL='postgres://user:pass@host:5432/db' npx goribu deploy

# Or as a flag
npx goribu deploy --postgres-url='postgres://user:pass@host:5432/db'

Find it under Neon's Connection Details, Supabase's Database → Direct connection (not the pooler), or your own postgres://… string. If type is "postgres" and no connection string is available, the deploy stops with an error naming both ways to set it. See Postgres for authoring migrations and zero-downtime patterns.

Building separately

goribu build is a standalone step for two reasons: inspecting dist/ (sizes, what prerendered, bundle-leak warnings) before committing, and CI pipelines that split build from deploy. --skip-build reuses existing output instead of rebuilding:

npx goribu build          # inspect dist/, check warnings…
npx goribu deploy --skip-build

Continuous deployment

Cloudflare Workers Builds connects a git repo and runs the build on Cloudflare on every push. Set its build command to npx goribu deploy to get migrations and secrets handled too. For a DIY pipeline, build in one job, share dist/ as an artifact and deploy with --skip-build downstream:

build:
  steps:
    - run: npx goribu build
    - uses: actions/upload-artifact@v4
      with: { name: dist, path: dist/ }
deploy:
  needs: build
  steps:
    - uses: actions/download-artifact@v4
      with: { name: dist, path: dist/ }
    - env: { POSTGRES_URL: ${{ secrets.POSTGRES_URL }} }
      run: npx goribu deploy --skip-build

Nothing is GitHub-specific so you can npx goribu deploy from any runner with wrangler authenticated works. The POSTGRES_URL is only needed for Postgres apps.

Rollbacks

Cloudflare keeps a version of every deploy:

npx wrangler rollback              # to the previous version
npx wrangler rollback <version-id> # to a specific one

Rollback is a Worker-only operation and it does not touch the database or undo migrations. If a migration was forward-incompatible with the previous Worker, the rolled-back code will hit a schema it doesn't expect, so prefer rolling forward with a fix migration.

Watching production

npx wrangler tail

streams request logs and console.* output from the live Worker in real time. Correlate a user-reported _500 errorId with its log line here.

What goribu deploy does, in order

  1. Builds the app (skipped with --skip-build).
  2. Loads .env.production so process.env.* resolves, then loads goribu.config.js.
  3. Resolves the database — D1: looks it up by name, creates it if missing, caches the UUID in .goribu/resources.json (self-healing: it refreshes if the live UUID differs). Postgres: uses hyperdriveId as-is; Goribu never provisions or modifies Hyperdrive.
  4. Writes the resolved bindings into .goribu/wrangler.deploy.jsonc, leaving the build output untouched.
  5. Runs pending migrations against the remote database when database.type is set.
  6. Shells out to wrangler deploy --config .goribu/wrangler.deploy.jsonc, adding --secrets-file=.env.production when that file exists.