Deploy to Cloudflare
Deploy the TanStack Start app as one Cloudflare Worker with hosted Supabase. Start with the TanStack Start app working locally. The Next.js template deploys through Vercel.
Before you deploy
Use your application's Cloudflare account, hosted Supabase project and test-mode billing configuration. Install the Cloudflare CLI and confirm your selected account:
npm i -g cf
cf --version
cf auth whoamiThe build output is compatible with cf 1.0.0-beta.14. If you are logged out,
run cf auth login, then check the account again. Stop if it is not the account
that should own your app. Check Worker size limits:
the included app is larger than the 3 MiB compressed free-plan limit. Do not
assume that a successful local build fits your plan.
Name the Worker and choose its origin
In , change nitro.cloudflare.wrangler.name from app to
your application's Worker name. The Cloudflare configuration is inside the
existing nitro(...) call. Keep the pinned compatibilityDate; changing it
changes Worker runtime behavior.
Record the intended HTTPS origin,
https://<worker-name>.<your-subdomain>.workers.dev. <your-subdomain> is
your account's workers.dev subdomain, shown on the Workers & Pages
overview in the Cloudflare dashboard. Use this origin for browser
configuration, Auth redirects and billing return URLs. A custom domain can
be configured later through Cloudflare.
Link Supabase and apply migrations
In the Supabase dashboard, create or select the hosted project for your application. Confirm its project name and reference before linking this checkout:
bunx supabase login
bunx supabase link --project-ref <your-project-ref>
bunx supabase migration list --linked
bunx supabase db push --linked --dry-runThe dry run lists pending migrations without applying them. For a new project, review that list, apply the template migrations, then check the migration history again:
bunx supabase db push --linked
bunx supabase migration list --linkedAll checked-in migration versions must appear in the remote history. For an existing or shared project, stop on an unexpected migration or schema mismatch and reconcile it before deploying. Do not reset an existing database.
Allow Auth redirects
Under Authentication → URL Configuration, add these exact Redirect URLs, replacing the example origin with your Worker origin:
https://<worker-name>.<your-subdomain>.workers.dev/auth/callback
https://<worker-name>.<your-subdomain>.workers.dev/auth/reset-password
https://<worker-name>.<your-subdomain>.workers.dev/dashboard/account?status=Success!&status_description=Your%20email%20has%20been%20updated.- The callback receives signup, email and OAuth returns.
- The reset URL receives password setup and recovery links.
- The account URL receives email-change confirmation, including the query string the app generates.
If the Worker is the project's only app, set Site URL to its HTTPS origin. When adding Workers to an existing shared project, preserve its Site URL and all existing redirect entries, and add the Worker URLs alongside them. Keep the configured provider callback in Supabase's OAuth settings unchanged. Test each enabled account flow at the Worker URL before advertising it.
Create the Hyperdrive configuration
Create a Hyperdrive configuration for this database by following Cloudflare's Supabase guide, or reuse an existing configuration that points to that exact database. Hyperdrive is a connection proxy; it does not create another database.
- Use the Supabase direct connection as its origin.
- Disable query caching so permissions and application reads use current database state.
- Keep origin TLS enabled. If the database uses a private CA, configure its trusted CA certificate rather than disabling TLS.
List your configurations and record the ID of the one for this database:
cf hyperdrive listSet that ID as CLOUDFLARE_HYPERDRIVE_ID in the deployment file below. The
build binds it as HYPERDRIVE; the Worker uses its connection string with
request-scoped clients and prepared statements.
Optional: register billing webhooks
Hosted billing and production email on Workers are not yet verified. You can deploy without them and add them later. If you configure billing now, stay in Stripe test mode or Polar sandbox and register a new hosted webhook destination for your provider at your Worker origin:
https://<worker-name>.<your-subdomain>.workers.dev/api/webhooks/stripe
https://<worker-name>.<your-subdomain>.workers.dev/api/webhooks/polarUse the signing secret of that hosted destination, never your local listener's secret.
Prepare deployment settings
Create an ignored deployment file from the example:
cp .env.example .env.cloudflareEdit locally with your provider values. Replace all loopback URLs and placeholders. Collect the Supabase values from the dashboard first:
- Under Connect, copy the hosted PostgreSQL connection for
DATABASE_URL; Supabase's connection guide helps you choose a connection type. The Worker itself connects through the Hyperdrive binding created above. - Under Project Settings → API Keys, copy the publishable and server-only secret keys, and note the project's API URL.
At minimum, configure:
| Setting | Value for this deployment |
|---|---|
NEXT_PUBLIC_APP_URL | The exact HTTPS Worker origin. |
NEXT_PUBLIC_SUPABASE_URL | Your hosted Supabase API URL. |
NEXT_PUBLIC_SUPABASE_PUBLISHABLE_KEY | The matching public key. |
DATABASE_URL | Your hosted Postgres connection for database tooling and Node. Server-only. |
CLOUDFLARE_HYPERDRIVE_ID | Existing Hyperdrive configuration ID for this same database; used at build time. |
SUPABASE_SECRET_KEY | The matching server-only Supabase key. |
EMAIL_DELIVERY_MODE | real, set before any flow sends email. |
PAYMENT_PROVIDER and the provider's keys | Optional for a first deploy; see the list below. |
Also set, for the same file:
- Email:
RESEND_API_KEYandRESEND_FROM_EMAIL. A production build rejects an unsetEMAIL_DELIVERY_MODEwhen it sends email. - Stripe:
PAYMENT_PROVIDER=stripewithSTRIPE_SECRET_KEY,STRIPE_WEBHOOK_SECRET,NEXT_PUBLIC_STRIPE_PUBLISHABLE_KEYandNEXT_PUBLIC_STRIPE_MODE. - Polar:
PAYMENT_PROVIDER=polarwith thePOLAR_*settings in .
leaves SUPABASE_SECRET_KEY commented out; uncomment it.
The deploy step uploads every setting in this file as a Worker secret, so
replace each replace_me placeholder you keep. Before you sell, also set
the product and price IDs for your offers: the commented
NEXT_PUBLIC_STRIPE_*_PRICE_ID* lines for Stripe, or the POLAR_*_PRODUCT_ID*
lines for Polar.
Only NEXT_PUBLIC_* settings are exposed to browser code. Database,
administrative, payment and email secrets remain server-side. Do not put
them in , commit the deployment file, or paste its values
into a shell command or support message.
Build and check the artifact
bun --env-file=.env.cloudflare run build:cloudflare
cf deploy --prebuilt --dry-runThe build uses Nitro's Workers preset, checks TypeScript, then prepares
the server modules and public assets under .cloudflare/output/ for the
Cloudflare CLI. It does not read . The dry run validates the
artifact without uploading it. Both commands must finish successfully.
Public values are fixed into the browser bundle during this build.
Rebuild whenever the public origin or other NEXT_PUBLIC_* values change.
Deploy the built app
cf deploy --prebuilt --secrets-file .env.cloudflareThe CLI uploads the prepared app and stores the supplied runtime settings as Worker secrets. It prints the deployed URL and version. Confirm the Worker name and URL match your intended app before testing it.
Verify the hosted app
Open the printed URL, then verify the parts of your product that you configured.
To sign in, first create an account at /signup with the email address of a
member of your Supabase project team. Supabase's default email service sends
confirmation email only to those addresses until you
configure custom SMTP.
| Check | Expected result |
|---|---|
| Home, pricing, Docs and Blog | Pages and assets load on a direct visit and refresh. |
/api/health | HTTP 200 with status: ok. This checks liveness only. |
| Sign in, reload, sign out | The session survives reload and protected pages require signin after logout. |
| Create a Project | The Project remains after refresh in the same Organization. |
| Your selected billing flow, if configured | Test checkout returns to the Worker origin and payment grants access. |
| Your application's social image | The emitted image URL returns an image rather than an error page. |
A successful deployment or health response does not prove authentication, database writes, payment handling or email delivery. Stop on a failed check; inspect the affected Worker request in Cloudflare logs before changing provider credentials or retrying a payment.
Update or recover
Rebuild and rerun the dry run before deploying a change. Keep the previous Cloudflare version until the new one passes your checks; use Cloudflare's rollback procedure if a deployed change fails. Do not reset Supabase to repair a Worker deployment.
What's next
Authentication
Get Support
Was this page helpful?