|
| 1 | +# Deploying to Modern Deno Deploy |
| 2 | + |
| 3 | +This project ships via **modern Deno Deploy** |
| 4 | +([console.deno.com](https://console.deno.com)) using GitHub integration — there |
| 5 | +is **no GitHub Actions deploy job**. Deno Deploy handles the build itself when |
| 6 | +commits land on the connected branch. |
| 7 | + |
| 8 | +> **Deno Deploy Classic shuts down 2026-07-20.** This repo has been migrated off |
| 9 | +> `deployctl@v1`. The classic project on `dash.deno.com` is not |
| 10 | +> auto-transferred; follow the runbook below before that date. |
| 11 | +
|
| 12 | +## Project settings to configure in console.deno.com |
| 13 | + |
| 14 | +| Setting | Value | |
| 15 | +| --------------- | -------------------------------------------- | |
| 16 | +| Build command | `deno task build` | |
| 17 | +| Install command | _(none — Deno fetches imports during build)_ | |
| 18 | +| Entrypoint | `main.ts` | |
| 19 | +| Root directory | `.` | |
| 20 | + |
| 21 | +The optional `deploy` block in [`deno.json`](deno.json) (`project: "denodevs"`, |
| 22 | +`entrypoint: "./main.ts"`, …) is the source of truth for include/exclude; the |
| 23 | +dashboard can read these as defaults. |
| 24 | + |
| 25 | +## Environment variables |
| 26 | + |
| 27 | +These must be configured in console.deno.com — the application reads them at |
| 28 | +module load (`utils/config.ts`) and will fail to boot if any required value is |
| 29 | +missing. |
| 30 | + |
| 31 | +### Required at **runtime** (production) |
| 32 | + |
| 33 | +| Variable | Purpose | |
| 34 | +| ------------------------------------------- | --------------------------------------------------------------- | |
| 35 | +| `SITE_BASE_URL` | Canonical site URL used for OAuth redirects, signed links, etc. | |
| 36 | +| `GITHUB_CLIENT_ID` / `GITHUB_CLIENT_SECRET` | GitHub OAuth app for developer sign-in. | |
| 37 | +| `GOOGLE_CLIENT_ID` / `GOOGLE_CLIENT_SECRET` | Google OAuth app for developer sign-in. | |
| 38 | +| `RESEND_API_KEY` | Resend API key for transactional email. | |
| 39 | +| `ADMIN_USERNAME` / `ADMIN_PASSWORD` | HTTP Basic credentials for `/admin/*`. | |
| 40 | +| `USE_SECURE_COOKIES` | `true` in production (required for `Secure` flag). | |
| 41 | +| `CLICKY_SITE_ID` | Clicky analytics site ID. | |
| 42 | + |
| 43 | +### Required at **build time** |
| 44 | + |
| 45 | +`utils/config.ts` runs `assertExists` on several env vars at module load, and |
| 46 | +the build evaluates that module. Set these in the Deno Deploy project's **Build |
| 47 | +Environment** with placeholder values (the real secrets bind at runtime): |
| 48 | + |
| 49 | +``` |
| 50 | +SITE_BASE_URL = http://localhost:8000 |
| 51 | +GITHUB_CLIENT_ID = build |
| 52 | +GITHUB_CLIENT_SECRET = build |
| 53 | +GOOGLE_CLIENT_ID = build |
| 54 | +GOOGLE_CLIENT_SECRET = build |
| 55 | +CLICKY_SITE_ID = build |
| 56 | +``` |
| 57 | + |
| 58 | +(Use the same set the old `.github/workflows/deploy.yml` was passing — they were |
| 59 | +always placeholders, never real secrets.) |
| 60 | + |
| 61 | +## Modern Deploy gotchas to know about |
| 62 | + |
| 63 | +- **2-region cap** on modern Deploy (vs Classic's 6). Pick the regions closest |
| 64 | + to the user base. |
| 65 | +- **Deno Deploy Classic Queues are unsupported** in modern Deploy. This app uses |
| 66 | + no `Deno.cron` and no queues, so we're unaffected — but don't add either |
| 67 | + expecting it to work. |
| 68 | +- **KV data is not automatically migrated.** See the cutover runbook below. |
| 69 | + |
| 70 | +## Cutover runbook (one-time) |
| 71 | + |
| 72 | +Execute these steps against the live environment after this branch lands. |
| 73 | + |
| 74 | +1. Sign into [console.deno.com](https://console.deno.com) with the account that |
| 75 | + owns the Classic project. |
| 76 | +2. Create a new **organization**. |
| 77 | +3. Create a new **project**, connect the `denodevs.com` GitHub repo, point at |
| 78 | + the production branch. |
| 79 | +4. Configure the build command (`deno task build`), entrypoint (`main.ts`), and |
| 80 | + the env vars above. |
| 81 | +5. Trigger a deploy from a **staging branch** first. You'll need to temporarily |
| 82 | + add the preview `*.deno.net` URL to the GitHub and Google OAuth apps' allowed |
| 83 | + callback URLs to test sign-in end-to-end. |
| 84 | +6. **KV data migration**: email `support@deno.com` to request a KV copy from the |
| 85 | + Classic project to the new one. There is no self-serve path. Do this |
| 86 | + **before** flipping DNS, and verify a few keys (`developers`, |
| 87 | + `employers_by_email`, `developer_sessions`) post-copy. |
| 88 | +7. Once the new deploy passes a smoke test on its `.deno.net` URL, add the |
| 89 | + production custom domain in console.deno.com, set the `_acme-challenge` |
| 90 | + CNAME, then update the apex/CNAME DNS to point at modern Deploy. DNS |
| 91 | + propagation can take up to 48h. |
| 92 | +8. During the cutover window, keep **both** OAuth callback URLs (Classic and |
| 93 | + modern) registered with GitHub and Google. Remove the Classic URLs after DNS |
| 94 | + settles. |
| 95 | +9. Smoke test once more on the production domain. Once green, **archive** (don't |
| 96 | + delete) the Classic project. Classic shuts down 2026-07-20 regardless. |
0 commit comments