Skip to content

Deployment

Production prerequisites, secrets, resources, and Worker domains.

StackShip deploys four Workers to the Cloudflare account that owns the stackship.run zone.

Domains

Worker Custom domain
stackship-web stackship.run
stackship-api api.stackship.run
stackship-mcp mcp.stackship.run
stackship-docs docs.stackship.run

Wrangler custom domains create the required DNS records and certificates. A hostname cannot already have a conflicting CNAME.

Database

The PlanetScale PostgreSQL database is linked through Hyperdrive configuration 397048f06dbc43c1a921c92258384a40, bound to the API Worker as HYPERDRIVE. Query caching is disabled on this configuration because it serves Better Auth sessions, permissions, organizations, and other consistency-sensitive reads.

Do not use SQL comments as cache hints. Cloudflare does not document them as a cache-control API. If product reads later benefit from caching, create a second cache-enabled Hyperdrive configuration and keep identity traffic on this cache-disabled binding.

The repository root contains an ignored .env.migrations file with the direct administrative connection:

DATABASE_URL=postgresql://…

Migration commands load this file explicitly:

pnpm db:generate
pnpm db:migrate

Never point .env.migrations at Hyperdrive or commit it to source control. PlanetScale’s sslrootcert=system URL parameter is normalized in memory for node-postgres; sslmode=verify-full remains enabled.

PlanetScale’s stable postgres role must own the application tables and the drizzle.__drizzle_migrations schema. The credential in .env.migrations must inherit PlanetScale’s postgres permission so Drizzle can perform DDL, but the credential itself must not become the long-lived object owner.

If a Hyperdrive or other integration role bootstraps the schema, use PlanetScale’s Reassign objects action to transfer its objects to postgres before running later migrations. Verify the transfer and run pnpm db:migrate before rotating or deleting the original role.

Secrets

Set Worker secrets without printing them:

wrangler secret put BETTER_AUTH_SECRET --config apps/api/wrangler.jsonc
wrangler secret put GOOGLE_CLIENT_ID --config apps/api/wrangler.jsonc
wrangler secret put GOOGLE_CLIENT_SECRET --config apps/api/wrangler.jsonc

Deploy

pnpm install
pnpm check
pnpm build
pnpm deploy

The first basic deployment can ship public health surfaces before database and identity credentials exist. In that state, auth returns 503 and MCP returns 401; neither service silently weakens its security posture.

Production checks

  • GET https://api.stackship.run/health checks Worker liveness and configured bindings.
  • GET https://api.stackship.run/ready connects through Hyperdrive and checks for the core Better Auth tables. It returns 503 with schema: migration_required until the generated migration is applied.
  • GET https://mcp.stackship.run/health checks MCP Worker liveness.
  • GET https://mcp.stackship.run/.well-known/oauth-protected-resource returns the OAuth protected-resource metadata.
Navigation

Type to search…

↑↓ navigate↵ selectEsc close