Cloudflare + Supabase deployment
Production notes for running TariffsChart on Cloudflare Workers with Supabase Postgres.
TariffsChart is configured for Cloudflare Workers + OpenNext with Supabase Postgres as the production database.
This page is an operational checklist. It does not change the product boundary: TariffsChart remains a planning, evidence, and review workflow, not a customs broker or guaranteed landed-cost engine.
What changed
The codebase now includes:
wrangler.jsoncfor Cloudflare Workers deployment;open-next.config.tsfor the OpenNext Cloudflare adapter;cloudflare-worker.ts, a custom Worker entrypoint that delegates normal requests to the OpenNext handler and adds ascheduled()handler for tariff source-monitor checks;cf:build,cf:preview,cf:deploy, andcf:typegenscripts inpackage.json;- Supabase-oriented PostgreSQL settings in
.env.exampleand.dev.vars.example; - Postgres client options that disable prepared statements and avoid cross-request singleton reuse in Cloudflare/serverless runtimes;
- optional Cloudflare Hyperdrive support through a
HYPERDRIVEbinding.
Recommended database path
For production Cloudflare Workers, the safest path is:
- Keep
DATABASE_PROVIDER=postgresql. - Use Supabase Postgres.
- Prefer a Cloudflare Hyperdrive binding named
HYPERDRIVEonce traffic is meaningful. - If Hyperdrive is not configured yet, use the Supabase Transaction Pooler connection string for
DATABASE_URLand keepprepare: false.
Example Supabase pooler URL:
DATABASE_URL=postgresql://postgres.PROJECT_REF:PASSWORD@aws-0-REGION.pooler.supabase.com:6543/postgres?sslmode=require
The app automatically prefers env.HYPERDRIVE.connectionString when that binding exists, and falls back to DATABASE_URL otherwise.
Cloudflare secrets
Do not put real secrets in wrangler.jsonc. Set them with Wrangler:
pnpm wrangler secret put DATABASE_URL
pnpm wrangler secret put AUTH_SECRET
pnpm wrangler secret put TARIFF_MONITOR_CRON_SECRET
pnpm wrangler secret put RESEND_API_KEY
Optional payment secrets should stay unset until self-serve checkout is intentionally opened:
pnpm wrangler secret put STRIPE_SECRET_KEY
pnpm wrangler secret put STRIPE_WEBHOOK_SECRET
pnpm wrangler secret put CREEM_API_KEY
pnpm wrangler secret put CREEM_WEBHOOK_SECRET
Local preview
Use .dev.vars.example as a template:
cp .dev.vars.example .dev.vars
Then run:
corepack enable
pnpm install
pnpm cf:preview
Migrations
Generate and run migrations against Supabase before production deploy:
pnpm db:generate
pnpm supabase:migrate
If you prefer pushing schema during a private beta:
pnpm supabase:push
Use migrations for production once real users exist.
Deploy
pnpm cf:build
pnpm cf:deploy
pnpm cf:deploy uses --keep-vars, so Cloudflare dashboard or Wrangler secrets are not overwritten during deploy.
Scheduled source-monitor checks
wrangler.jsonc defines a daily cron trigger:
"triggers": {
"crons": ["0 10 * * *"]
}
The custom Worker scheduled() handler calls:
POST /api/tariff/source-monitors/run
Set one of these secrets before relying on scheduled checks:
TARIFF_MONITOR_CRON_SECRET=replace-with-random-secret
# optional fallback
CRON_SECRET=replace-with-random-secret
Manual checks from /workspace/alerts still work for Pro beta and Team pilot users even if scheduled checks are not enabled.
Hyperdrive setup, optional but recommended
Create a Hyperdrive configuration pointing at Supabase’s direct Postgres connection string, then add this binding to wrangler.jsonc:
"hyperdrive": [
{
"binding": "HYPERDRIVE",
"id": "<cloudflare-hyperdrive-id>"
}
]
When HYPERDRIVE is bound, TariffsChart uses that connection string automatically.
Launch checklist
Before production launch:
- run
pnpm installsopnpm-lock.yamlincludes@opennextjs/cloudflare; - run
pnpm lintandpnpm buildlocally or in CI; - run
pnpm cf:previewagainst a staging Cloudflare Worker; - run migrations against Supabase;
- confirm auth callback URLs use
https://tariffschart.com; - set Cloudflare secrets;
- verify scheduled monitor checks in Cloudflare logs;
- keep public checkout disabled until billing, webhook, downgrade, refund, and legal review flows are ready.