Deploy to Deno Deploy

Drop on Deno Deploy, with a Cloudflare D1 database and an S3-compatible bucket for files, like Cloudflare R2 or Amazon S3.

DatabaseD1 over HTTP
FilesR2 S3 API
Rate limitsPer instance
Code imagesSVG
Code image cleanupNone
LiveNot deployed yet

What you need

  • A Deno Deploy organization, and Deno 2.4 or newer signed in to it, for deno deploy.
  • A Cloudflare account and Wrangler (pnpm exec wrangler login).
  • An S3-compatible bucket and an access key for it. Deno Deploy has no file storage of its own.
  • Node.js 24 and pnpm, to build.
  • A GitHub OAuth app with the callback https://<your-app-domain>/api/auth/callback/github.

Deploy

  1. Get the code:

    npx giget gh:vite-hub/drop my-drop
    cd my-drop
    pnpm install
  2. Create the D1 database and apply its migrations:

    pnpm exec wrangler d1 create vitehub-drop-deno   # copy the id into CLOUDFLARE_D1_DATABASE_ID
    CLOUDFLARE_D1_DATABASE_NAME=vitehub-drop-deno pnpm db:migrate:d1
  3. Create a bucket. With Cloudflare R2:

    pnpm exec wrangler r2 bucket create vitehub-drop-deno

    Then create an R2 API token with Object Read and Write on that bucket, under R2, Manage API tokens. It gives you an access key id and a secret.

  4. Build for Deno. The bucket's name and endpoint are read at build time:

    DROP_HOST=deno S3_BUCKET=vitehub-drop-deno S3_ENDPOINT=https://<account-id>.r2.cloudflarestorage.com pnpm build
  5. Deploy. ViteHub writes .output/deploy.mjs, which creates the app on the first run (entrypoint server/index.mjs, with the traced node_modules) and deploys it to production:

    DENO_DEPLOY_ORG=<your-org> DENO_DEPLOY_APP=my-drop node .output/deploy.mjs
  6. Add the settings, then deploy again so the app picks them up:

    deno deploy env add --org <your-org> --app my-drop CLOUDFLARE_ACCOUNT_ID "…"
    deno deploy env add --org <your-org> --app my-drop CLOUDFLARE_API_TOKEN "…" --secret
    deno deploy env add --org <your-org> --app my-drop CLOUDFLARE_D1_DATABASE_ID "…"
    deno deploy env add --org <your-org> --app my-drop CLOUDFLARE_D1_DATABASE_NAME "vitehub-drop-deno"
    deno deploy env add --org <your-org> --app my-drop AWS_ACCESS_KEY_ID "…"
    deno deploy env add --org <your-org> --app my-drop AWS_SECRET_ACCESS_KEY "…" --secret
    deno deploy env add --org <your-org> --app my-drop GITHUB_CLIENT_ID "…"
    deno deploy env add --org <your-org> --app my-drop GITHUB_CLIENT_SECRET "…" --secret
    deno deploy env add --org <your-org> --app my-drop BETTER_AUTH_SECRET "$(openssl rand -base64 32)" --secret
    deno deploy env add --org <your-org> --app my-drop DROP_ADMINS "…"
  7. Run the smoke test:

    DROP_URL=https://my-drop.<your-org>.deno.net pnpm test:e2e:deployed

Settings

VariableWhat it is
GITHUB_CLIENT_IDYour GitHub OAuth app's client ID.
GITHUB_CLIENT_SECRETA client secret from the same app.
BETTER_AUTH_SECRETSigns sessions and agent tokens. One per deployment: openssl rand -base64 32
DROP_ADMINSGitHub user ids that join as Admin, comma-separated: gh api users/<login> --jq .id
CLOUDFLARE_ACCOUNT_ID, CLOUDFLARE_API_TOKENCloudflare account id and an account API token with D1 edit access.
CLOUDFLARE_D1_DATABASE_ID, CLOUDFLARE_D1_DATABASE_NAMEThe id and name of vitehub-drop-deno.
S3_BUCKET, S3_ENDPOINT, S3_REGIONThe bucket, its endpoint, and its region (auto for R2). Read at build time.
AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEYThe bucket's access key.

Database

Cloudflare D1 over HTTPS. pnpm db:migrate:d1 applies new migrations and skips the ones already applied; run it before you deploy a schema change.

On Deno Deploy

  • Code images are SVG only: PNG needs Cloudflare Browser Run.
  • Rate limits count in memory per isolate, so they're looser than on Cloudflare.
  • Nothing deletes expired code images: ViteHub has no scheduled jobs on Deno Deploy yet. They stop being served after five minutes, but stay in the bucket; a lifecycle rule on code-images/ cleans them up.