> ## Documentation Index
> Fetch the complete documentation index at: https://supastack.dev/llms.txt
> Use this file to discover all available pages before exploring further.
> For the full documentation corpus in one file, fetch: https://supastack.dev/llms-full.txt

# Set up custom domains

Let workspaces serve the app on their own hostnames via Cloudflare for SaaS.

## Setup and configuration

Before any step, read [Before you start](https://supastack.dev/docs/web/before-you-start.md) and [Terminal basics](https://supastack.dev/docs/web/terminal-basics.md). These instructions assume you opened the full supastack monorepo in VS Code; its root package.json marks the repository root. In pnpm commands, a workspace package is an app or shared-code folder; in the product, a workspace is a team's data container and security boundary. corepack pnpm --filter ... selects one package from the monorepo while commands run from its root. If you opened only a synced mobile or desktop folder, it does not contain the Web backend, Docker setup, or root scripts: run the backend from this monorepo or a reachable hosted server, and use the platform folder's own scripts. An environment variable is a named setting stored in a local .env file or your hosting dashboard; restart the relevant app after changing it, and keep server secrets out of NEXT_PUBLIC_ and EXPO_PUBLIC_ values.

1. Open apps/web/.env.local and use CUSTOM_DOMAINS_PROVIDER=local to preview the Domains screen without DNS changes.

2. For a real customer hostname, configure Cloudflare for SaaS with your own zone, an API token limited to that zone, and the CNAME target; enter the server-only values on the Web host, not in the browser.

3. Run Web with corepack pnpm --filter @supastack/web dev and open Settings → Domains as a workspace owner/admin. Expected: the local adapter activates a test domain immediately; the Cloudflare adapter waits for the displayed DNS records.

Set CUSTOM_DOMAINS_PROVIDER=cloudflare with CLOUDFLARE_API_TOKEN, CLOUDFLARE_ZONE_ID, and CUSTOM_DOMAIN_CNAME_TARGET. The API token needs SSL and Certificates:Edit permission on the zone (the Custom Hostnames API lives under /zones/{zone_id}/custom_hostnames). The CNAME target is a hostname in your Cloudflare zone — for example customers.example.com — that resolves to your deployed app.

Add a DNS record in the zone pointing the CNAME target at your origin (the fallback origin in Cloudflare for SaaS terms). Cloudflare issues each custom hostname a DCV TXT record plus an optional ownership TXT record; the settings screen shows customers exactly which records to create.

For local development use CUSTOM_DOMAINS_PROVIDER=local, which marks every hostname active immediately with target customers.localhost. CUSTOM_DOMAINS_PROVIDER=off (the default) hides the section's controls.

```
CUSTOM_DOMAINS_PROVIDER=cloudflare
CLOUDFLARE_API_TOKEN=cf_token_with_ssl_edit
CLOUDFLARE_ZONE_ID=zone_id
CUSTOM_DOMAIN_CNAME_TARGET=customers.example.com
```


## Commands to copy

Follow the comments to see which folder a command runs in. If two terminals are labeled, open two terminal windows and keep the first command running while you use the second.

```
corepack pnpm --filter @supastack/web dev
```


## Implementation workflow

Workspace owners and admins manage domains under Settings → Domains (five per workspace). Customers point a CNAME record for their hostname at the CNAME target, add the TXT records shown for ownership and certificate validation, then press Refresh status. Once Cloudflare reports the hostname active it becomes a trusted origin for auth on that deployment and the workspace name/logo brand the app chrome on that hostname.

Apex (root) domains cannot be CNAMEs at most DNS providers — customers should use a subdomain such as portal.example.com, or a provider with CNAME flattening. Cookies stay scoped to each host, so a customer domain is a separate sign-in; single sign-on across custom domains is out of scope.


## Verification and troubleshooting

If Cloudflare stays pending, compare the customer's CNAME and TXT records with the exact values shown on the domain card and allow DNS time to update. Use a subdomain when the DNS provider cannot flatten a root-domain CNAME. If the menu is absent, check that the feature is enabled and the signed-in user is a workspace owner or admin.

Pending for a long time usually means the customer's CNAME is missing or still propagating — re-check the DNS records shown on the domain card. A moved or failed status means Cloudflare can no longer resolve the hostname to the zone; remove and re-add it. Validation data is stored as provider JSON so future Cloudflare validation shapes need no schema change.


If you want to continue setup, read [Deploy to Google Cloud](https://supastack.dev/docs/web/deploy-google-cloud.md).


## Next

[Deploy to Google Cloud](https://supastack.dev/docs/web/deploy-google-cloud.md)
