# Netlify and Cloudflare

> Deploy apps on Netlify, Cloudflare Pages or Cloudflare Workers against a SupaHost project. Environment variables, redirect URLs for previews, a Worker example, and DNS settings for custom domains.

Source: https://supahost.app/docs/integrations/netlify-cloudflare · Updated 2026-11-11

Netlify and Cloudflare both run your frontend and server code close to users and call your SupaHost project over HTTPS. supabase-js works in Netlify Functions, Netlify Edge Functions, Cloudflare Workers and Pages Functions, because it only needs `fetch`.

## Netlify

### Environment variables

In the Netlify UI, open your site, go to **Site configuration → Environment variables**, and add the values from your SupaHost project's **Connect** tab (subtab **App**). Use the prefix your framework expects for values the browser needs, for example:

```bash
# Vite / React / Vue
VITE_SUPABASE_URL=https://app-one.acme.supahost.space
VITE_SUPABASE_ANON_KEY=eyJhbGciOiJIUzI1NiIs...
```

Or with the Netlify CLI:

```bash
netlify env:set VITE_SUPABASE_URL https://app-one.acme.supahost.space
netlify env:set VITE_SUPABASE_ANON_KEY eyJhbGciOiJIUzI1NiIs...
netlify env:set SUPABASE_SERVICE_ROLE_KEY eyJhbGciOiJIUzI1NiIs... --secret
```

The `service_role` key belongs only in variables read by server-side Functions, never in a `VITE_` or other public variable. You can scope variables to deploy contexts (production, deploy previews, branch deploys) to point previews at a separate staging project.

### Redirect URLs for deploy previews

Netlify previews live at addresses like `https://deploy-preview-42--recipe-box.netlify.app`. On the SupaHost project's **Auth** tab, add patterns under **Redirect URLs** that cover them, then click **Save Auth settings**:

```text
https://recipes.example.com/**
https://*--recipe-box.netlify.app/**
http://localhost:8888/**
```

Set **Site URL** to your production domain. In code, use `window.location.origin` (browser) or Netlify's `URL` and `DEPLOY_PRIME_URL` build variables to build `redirectTo` values, so each preview returns to itself.

### Functions region

Netlify Functions run in one region per site, which you can change under the site's Functions settings. Choose the one nearest your SupaHost instance's region (shown on the dashboard's **Instance** page) to keep each query's round trip short.

## Cloudflare Workers and Pages

### A Worker that reads from SupaHost

```bash
npm create cloudflare@latest recipe-api
cd recipe-api
npm install @supabase/supabase-js
```

```ts
// src/index.ts
import { createClient } from '@supabase/supabase-js'

interface Env {
  SUPABASE_URL: string
  SUPABASE_ANON_KEY: string
}

export default {
  async fetch(request: Request, env: Env): Promise<Response> {
    // Forward the caller's token, if any, so RLS sees the right user.
    const authorization = request.headers.get('Authorization')
    const supabase = createClient(env.SUPABASE_URL, env.SUPABASE_ANON_KEY, {
      auth: { persistSession: false, autoRefreshToken: false },
      global: authorization ? { headers: { Authorization: authorization } } : undefined,
    })

    const { data, error } = await supabase
      .from('recipes')
      .select('id, title, minutes')
      .order('created_at', { ascending: false })
      .limit(20)

    if (error) return Response.json({ error: error.message }, { status: 500 })
    return Response.json(data, { headers: { 'Cache-Control': 'public, max-age=60' } })
  },
}
```

If there's no caller token, supabase-js falls back to the `anon` key. Create the client inside `fetch`, since `env` is only available there and each request may carry a different user.

Set the values with Wrangler. Plain settings go in `wrangler.jsonc`; secrets go through the CLI so they aren't committed:

```jsonc
// wrangler.jsonc (excerpt)
{
  "vars": {
    "SUPABASE_URL": "https://app-one.acme.supahost.space"
  },
  "placement": { "mode": "smart" }
}
```

```bash
npx wrangler secret put SUPABASE_ANON_KEY
npx wrangler deploy
```

Smart Placement lets Cloudflare run the Worker near the backend it talks to, which helps when one request makes several calls to SupaHost.

Cloudflare Pages works the same way. Add variables under the Pages project's settings, and read them from `context.env` in Pages Functions or through your framework's usual env prefix for browser code.

### Hyperdrive doesn't apply

Cloudflare Hyperdrive and Postgres drivers in Workers need to reach your database over the internet. SupaHost doesn't expose Postgres publicly (Business and Enterprise get an SSH tunnel for developer tools, not for app servers), so use supabase-js and the Data API from Workers.

### Redirect URLs

Pages previews use addresses like `https://<hash>.recipe-box.pages.dev`. Add `https://*.recipe-box.pages.dev/**` and your production domain under **Redirect URLs** on the Auth tab.

## Custom domains with Cloudflare DNS

You can serve your SupaHost project's API from your own domain, such as `api.recipes.example.com`, from the project's **Domains** tab. If your DNS is on Cloudflare:

1. Create a `CNAME` record from `api` to your project host, `app-one.acme.supahost.space`.
2. Set the record to **DNS only** (grey cloud), not Proxied.
3. Wait for the domain to show as active on the Domains tab. SupaHost checks DNS about once a minute and then issues a Let's Encrypt certificate.

SupaHost has to answer HTTPS for the hostname itself to get the certificate, so a proxied record keeps the domain from verifying. Your app's own site can still be proxied by Cloudflare; only the record pointing at SupaHost must be DNS only.

## Related

- [Custom domains](/docs/platform/custom-domains)
- [Custom domain behind Cloudflare proxy](/kb/cloudflare-proxy-custom-domain)
- [Site URL and redirect URLs](/docs/auth/redirect-urls)
- [Can I connect from serverless and edge functions?](/kb/serverless-edge-connections)
