Deploy to Cloudflare Workers
Run Session Canvas on Cloudflare's edge via OpenNext — a working path with a few documented caveats.
Session Canvas runs on Cloudflare Workers through OpenNext. The repo ships the pieces: wrangler.jsonc, open-next.config.ts, and scripts/cloudflare-build.mjs, which wraps the build and papers over a few gaps between Next.js 16 and the current adapter.
Deploy
Log in to Cloudflare
pnpm wrangler login
Create the R2 bucket that backs the ISR cache
The public embed pages revalidate every 5 minutes through an R2-backed cache (R2 has to be enabled once for your account in the Cloudflare dashboard):
pnpm wrangler r2 bucket create sessioncanvas-inc-cache
Set the environment variables as Worker secrets
pnpm wrangler secret put DATABASE_URL pnpm wrangler secret put DIRECT_URL pnpm wrangler secret put NEXT_PUBLIC_SUPABASE_URL pnpm wrangler secret put NEXT_PUBLIC_SUPABASE_ANON_KEY pnpm wrangler secret put SUPABASE_SERVICE_ROLE_KEY pnpm wrangler secret put RESEND_API_KEY pnpm wrangler secret put EMAIL_FROM pnpm wrangler secret put NEXT_PUBLIC_APP_URL
Recommended: put Hyperdrive in front of Postgres
Workers can’t reuse a TCP connection across requests, so without a pooler every request pays a fresh TLS handshake to your database:
pnpm wrangler hyperdrive create sessioncanvas-hyperdrive \ --connection-string="$DIRECT_URL"
Add the binding to
wrangler.jsonc:"hyperdrive": [{ "binding": "HYPERDRIVE", "id": "<id from the create command>" }]Then prefer the binding’s connection string in
src/lib/db.ts:import { getCloudflareContext } from "@opennextjs/cloudflare"; // inside createPrismaClient(), replace process.env.DATABASE_URL with: const connectionString = isWorkerd ? getCloudflareContext().env.HYPERDRIVE.connectionString : process.env.DATABASE_URL;Deploy
pnpm deploy:cf # build + wrangler deploy
To try it locally first,
pnpm preview:cfruns the real Worker build in workerd viawrangler dev, reading env vars from.dev.vars(copy your.env).Migrate, seed, and allow the Workers URL in Supabase
Run
pnpm db:migrate(and optionallypnpm db:seed) against the production database, and add your Workers URL to Supabase’s Authentication → URL Configuration → Redirect URLs — exactly as in the Vercel steps.
Known caveats
- The OpenNext adapter (1.20.x) doesn’t support Next 16’s Node.js
proxy.tsyet, so the Cloudflare build temporarily swaps in an equivalent edge-runtimemiddleware.tsshim (same logic and matchers, restored after the build). - The build script regenerates the Prisma client with
runtime = "workerd"and patches Turbopack’s WASM loading for it — see the header comments inscripts/cloudflare-build.mjs. - In-Worker Postgres connections are deliberately not reused across requests (workerd forbids it) — use Hyperdrive for production traffic.
- ISR revalidation runs through a Durable Object queue shipped inside the worker — nothing to create account-side.
- Smoke-tested in workerd against a live Supabase database: home page, public CFP form, event pages, schedule embed (with ISR caching), admin shell, and the JSON/iCal feeds. Not yet exercised end-to-end on Workers: email sending, magic-link sign-in, file upload / ZIP export, and Airtable sync. Prefer Vercel if those must be battle-tested today.
- Scheduled jobs (task reminders, Airtable sync) are registered as Vercel crons in
vercel.json. On Workers, call the endpoints from a Cloudflare Cron Trigger or any external scheduler, sendingAuthorization: Bearer $CRON_SECRET.