From 86b7b7c50962c851bf648be22a70a8f0427a3638 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Bramer=20Schmidt?= Date: Fri, 16 Oct 2026 21:12:32 +0700 Subject: [PATCH 1/3] docs(compute): document custom domains on branches --- .../docs/content/docs/cli/error-reference.mdx | 6 +----- apps/docs/content/docs/cli/service.mdx | 2 +- .../content/docs/compute/deploy-on-push.mdx | 2 +- .../docs/content/docs/compute/deployments.mdx | 2 +- apps/docs/content/docs/compute/domains.mdx | 20 +++++++++++++------ apps/docs/content/docs/compute/faq.mdx | 6 +++--- .../docs/content/docs/compute/limitations.mdx | 2 +- 7 files changed, 22 insertions(+), 18 deletions(-) diff --git a/apps/docs/content/docs/cli/error-reference.mdx b/apps/docs/content/docs/cli/error-reference.mdx index 7826e1ee825..d9a999d6e00 100644 --- a/apps/docs/content/docs/cli/error-reference.mdx +++ b/apps/docs/content/docs/cli/error-reference.mdx @@ -452,10 +452,6 @@ A `project` or `branch` group command was invoked with unusable arguments — fo A `--branch` flag was passed with an empty or whitespace-only value to a service command; the check runs before any resolution because a blank value must never fall through to the default-branch behavior of omitting the flag. The fix is to pass a non-empty branch name, or omit `--branch` to target the default branch. Meta: none. -### SERVICE.BRANCH_NOT_DEPLOYABLE [#SERVICE.BRANCH_NOT_DEPLOYABLE] - -A `service domain` command was pointed at a non-production branch, which the domain-target resolver refuses because custom domains on preview branches are not supported in Public Beta. The fix is to use `--branch production`, or attach the domain after promoting to the production branch. Meta: none. - ### SERVICE.DELETE_FAILED [#SERVICE.DELETE_FAILED] `service delete` called the platform's app-teardown API and it rejected; the underlying error's message becomes `why` and the original error is carried in `cause`. Next actions point at `service show` and `service version list` for the service. Meta: none. @@ -530,7 +526,7 @@ A `service logs` response body ended without the terminal record that closes a p ### SERVICE.NO_VERSIONS [#SERVICE.NO_VERSIONS] -The resolved service has no usable version for the command — raised by `service open` when the service has no versions, by `service logs` when it has no live version, and by `service domain add` when the API answers 422 because the production service has no promoted version that can receive a custom domain. The fix on the domain path is to promote a version on the production branch first, then add the domain again. Meta: `status`, `apiCode`, `hint` (domain-add path only; otherwise none). +The resolved service has no usable version for the command — raised by `service open` when the service has no versions, by `service logs` when it has no live version, and by `service domain add` when the API answers 422 because the selected service has no promoted version that can receive a custom domain. The fix on the domain path is to promote a version on the selected branch first, then add the domain again. Meta: `status`, `apiCode`, `hint` (domain-add path only; otherwise none). ### SERVICE.SELECTION_INVALID [#SERVICE.SELECTION_INVALID] diff --git a/apps/docs/content/docs/cli/service.mdx b/apps/docs/content/docs/cli/service.mdx index 698138569e2..9d67bbf6976 100644 --- a/apps/docs/content/docs/cli/service.mdx +++ b/apps/docs/content/docs/cli/service.mdx @@ -46,7 +46,7 @@ Promotion rebuilds the version with production environment variables, so configu ## service domain -Use `service domain` commands to manage custom domains for a service. All commands take a `` argument plus the usual service and project selectors and a `--branch ` scope. Domains target the production branch by default. See [Domains](/compute/domains) for details. +Use `service domain` commands to manage custom domains for a service. All commands take a `` argument plus the usual service and project selectors and a `--branch ` scope. Domains target the production branch by default. Pass `--branch ` to manage domains on a preview or staging branch. See [Domains](/compute/domains) for details. | Command | Description | | ---------------------------------- | --------------------------------------------------------------- | diff --git a/apps/docs/content/docs/compute/deploy-on-push.mdx b/apps/docs/content/docs/compute/deploy-on-push.mdx index 79527138018..aef1e9d7463 100644 --- a/apps/docs/content/docs/compute/deploy-on-push.mdx +++ b/apps/docs/content/docs/compute/deploy-on-push.mdx @@ -14,7 +14,7 @@ This guide sets that up for a [Prisma Composer](/composer) app that you deploy t When the workflow from this guide runs, each Git branch you push, other than the default one, becomes its own environment next to production. The preview gets the following, separate from production: -- **Its own deployment and URL.** The deploy action deploys the branch as a preview named after it, and the workflow run prints the preview's URL in its deploy report. Custom domains attach to production only, so a preview is reached at its generated URL. +- **Its own deployment and URL.** The deploy action deploys the branch as a preview named after it, and the workflow run prints the preview's URL in its deploy report. A preview has its own generated URL and can also use a [custom domain](/compute/domains). - **The whole app, not only the frontend.** Every service your module declares, such as a frontend and an API, runs in the preview as its own service. The code is the only thing a preview shares with production. - **Preview environment variables.** Every preview reads the preview-scoped values, and a branch override changes a value for one branch; production values are used only by production. See [Environment variables](/compute/environment-variables). - **Its own databases.** Each Prisma Postgres database your module declares is created for the branch, so what you write in the preview stays out of the production database. Don't assume production data is copied into it. If the app reads its connection string from a variable such as `DATABASE_URL` instead, the preview is only as separate as that value, so set a preview-scoped `DATABASE_URL` that points at a non-production database. diff --git a/apps/docs/content/docs/compute/deployments.mdx b/apps/docs/content/docs/compute/deployments.mdx index df872d2e6ec..9d49d85d0f3 100644 --- a/apps/docs/content/docs/compute/deployments.mdx +++ b/apps/docs/content/docs/compute/deployments.mdx @@ -82,5 +82,5 @@ This permanently deletes the service from the branch you target with `--branch`. - [Environment variables](/compute/environment-variables): persist config across deploys. - [Deploy on push](/compute/deploy-on-push): the push-to-deploy flow in detail. -- [Domains](/compute/domains): point a custom domain at production. +- [Domains](/compute/domains): point a custom domain at an app on any branch. - [Prisma Composer](/composer): declare the app the `deploy` command deploys. diff --git a/apps/docs/content/docs/compute/domains.mdx b/apps/docs/content/docs/compute/domains.mdx index 5bda7f20a5c..bfbef1e33d5 100644 --- a/apps/docs/content/docs/compute/domains.mdx +++ b/apps/docs/content/docs/compute/domains.mdx @@ -1,22 +1,22 @@ --- title: Domains -description: Point a custom domain at a production app and the platform verifies DNS and provisions TLS for you. +description: Point a custom domain at an app on any branch and the platform verifies DNS and provisions TLS for you. url: /compute/domains metaTitle: Custom domains | Prisma Compute metaDescription: Add a custom domain to a Prisma Compute app, configure the CNAME record, watch provisioning, and troubleshoot failures. --- -Configure custom domains that point to your [production app](/compute/branching). You can't configure custom domains for preview apps. +Configure custom domains for apps on [production, preview, or staging branches](/compute/branching). Each domain routes to the live deployment of the app on the selected branch. ## Before you start You'll need: - A [linked project](/compute/getting-started). -- A production app with a [promoted, running deployment](/compute/deployments). +- An app with a [promoted, running deployment](/compute/deployments). - Access to edit DNS records within your DNS provider. -Domain commands target the [production branch](/compute/branching). Pointing them at any other branch fails with a `BRANCH_NOT_DEPLOYABLE` error. Every domain subcommand also accepts `--project` and `--branch` flags. +Domain commands default to the production branch. To manage domains on another branch, pass `--branch ` to each command. See the [`service domain` reference](/cli/service#service-domain) for selectors and flags. ## Add a custom domain @@ -26,6 +26,15 @@ Domain commands target the [production branch](/compute/branching). Pointing the npx prisma service domain add shop.acme.com --service web ``` +For a staging branch, use: + +```npm +npx prisma service domain add staging.acme.com --service web --branch staging +npx prisma service domain wait staging.acme.com --service web --branch staging +``` + +In Console, select the branch and open the app's **Domains** page to add or remove a custom domain. + Registration verifies DNS up front. If the **CNAME** record isn't visible yet, the command fails with a `DOMAIN_DNS_NOT_CONFIGURED` error and prints the record name and value for you to create. Re-running `add` for a hostname that's already attached is safe: it shows the existing domain instead of failing. ### 2. Create CNAME Record @@ -82,7 +91,6 @@ A domain moves through these states: ## Limits -- Custom domains are only available on production apps. - DNS uses CNAME records only. Apex domains need a DNS provider that supports CNAME-like records (ALIAS, ANAME, or CNAME flattening) at the apex. - Wildcard hostnames such as `*.acme.com` are rejected. - Up to 3 custom domains per app. Adding more returns `DOMAIN_QUOTA_EXCEEDED`. @@ -99,6 +107,6 @@ npx prisma service domain retry shop.acme.com --service web ## Next steps -- [Deployments](/compute/deployments): promote a deployment to production first. +- [Deployments](/compute/deployments): make a deployment live on the selected branch first. - [Known limitations](/compute/limitations): what Compute can and can't do. - [`service domain` reference](/cli/service#service-domain): every domain subcommand and flag. diff --git a/apps/docs/content/docs/compute/faq.mdx b/apps/docs/content/docs/compute/faq.mdx index 2236ed83035..7f491e7a7b0 100644 --- a/apps/docs/content/docs/compute/faq.mdx +++ b/apps/docs/content/docs/compute/faq.mdx @@ -42,7 +42,7 @@ This is the full list of what Compute and Prisma Postgres do not do today. - No point-in-time recovery on Prisma Postgres. Paid plans take daily snapshots, kept 7 days on Starter and Pro and 30 days on Business; the Free plan has no backups, and restoring to an arbitrary moment is not available yet. `pg_dump` over a direct connection makes your own copies; see [Backups](/postgres/database/backups). - No query cache. Prisma Postgres includes connection pooling but has no query cache of its own. - Previews are not copies of production. A preview branch gets its own database with no production data in it; the deploy applies your `migrations/` to a Composer `postgres()` database before the service starts, and a `rawPostgres()` database is yours to migrate. -- Custom domains are production-only. They attach to the default branch by CNAME, the service needs a promoted version first, and each service can have up to 3. +- Custom domains use CNAME records. Each service can have up to 3 domains on any branch and needs a promoted, running version first. [Known limitations](/compute/limitations) lists the same items with the CLI, environment variable, GitHub and log details. @@ -157,7 +157,7 @@ The current directory isn't linked to a project, and the CLI won't guess one fro ## How do I add a custom domain? -Once the service has a running production version: +Once the service has a promoted, running version: ```npm npx prisma service domain add shop.acme.com --service web @@ -168,7 +168,7 @@ Add the CNAME record the command returns at your DNS provider. To learn more, se ## Can preview branches have custom domains? -No, custom domains are production-only, so they cannot be attached to preview branches. +Yes. Select the preview branch in Console and open the app's **Domains** page, or pass `--branch ` to each `service domain` command. The app needs a promoted, running deployment. See [Domains](/compute/domains) for setup steps. ## Does Prisma clone my production database for previews? diff --git a/apps/docs/content/docs/compute/limitations.mdx b/apps/docs/content/docs/compute/limitations.mdx index 139cb04e5eb..f0bb79b5ab9 100644 --- a/apps/docs/content/docs/compute/limitations.mdx +++ b/apps/docs/content/docs/compute/limitations.mdx @@ -43,7 +43,7 @@ This page lists what Prisma Compute can and can't do. ## Domains -- Custom domains are production-only and CNAME-based: they attach to the default (production) branch, and the service needs a promoted version first. +- Custom domains use CNAME records and can attach to a service on any branch. The service needs a promoted, running version first. - Up to 3 custom domains per service. - There is no workspace-wide domain list in the CLI. From 45dfeadcff2e675a09be42383532e7eca9038be7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Bramer=20Schmidt?= Date: Fri, 16 Oct 2026 21:15:14 +0700 Subject: [PATCH 2/3] docs(cli): keep the current error reference until CLI release --- apps/docs/content/docs/cli/error-reference.mdx | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/apps/docs/content/docs/cli/error-reference.mdx b/apps/docs/content/docs/cli/error-reference.mdx index d9a999d6e00..7826e1ee825 100644 --- a/apps/docs/content/docs/cli/error-reference.mdx +++ b/apps/docs/content/docs/cli/error-reference.mdx @@ -452,6 +452,10 @@ A `project` or `branch` group command was invoked with unusable arguments — fo A `--branch` flag was passed with an empty or whitespace-only value to a service command; the check runs before any resolution because a blank value must never fall through to the default-branch behavior of omitting the flag. The fix is to pass a non-empty branch name, or omit `--branch` to target the default branch. Meta: none. +### SERVICE.BRANCH_NOT_DEPLOYABLE [#SERVICE.BRANCH_NOT_DEPLOYABLE] + +A `service domain` command was pointed at a non-production branch, which the domain-target resolver refuses because custom domains on preview branches are not supported in Public Beta. The fix is to use `--branch production`, or attach the domain after promoting to the production branch. Meta: none. + ### SERVICE.DELETE_FAILED [#SERVICE.DELETE_FAILED] `service delete` called the platform's app-teardown API and it rejected; the underlying error's message becomes `why` and the original error is carried in `cause`. Next actions point at `service show` and `service version list` for the service. Meta: none. @@ -526,7 +530,7 @@ A `service logs` response body ended without the terminal record that closes a p ### SERVICE.NO_VERSIONS [#SERVICE.NO_VERSIONS] -The resolved service has no usable version for the command — raised by `service open` when the service has no versions, by `service logs` when it has no live version, and by `service domain add` when the API answers 422 because the selected service has no promoted version that can receive a custom domain. The fix on the domain path is to promote a version on the selected branch first, then add the domain again. Meta: `status`, `apiCode`, `hint` (domain-add path only; otherwise none). +The resolved service has no usable version for the command — raised by `service open` when the service has no versions, by `service logs` when it has no live version, and by `service domain add` when the API answers 422 because the production service has no promoted version that can receive a custom domain. The fix on the domain path is to promote a version on the production branch first, then add the domain again. Meta: `status`, `apiCode`, `hint` (domain-add path only; otherwise none). ### SERVICE.SELECTION_INVALID [#SERVICE.SELECTION_INVALID] From 64c04e12d0ccbe2382a882048705871e977976b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?S=C3=B8ren=20Bramer=20Schmidt?= Date: Sat, 24 Oct 2026 16:24:00 +0700 Subject: [PATCH 3/3] docs(compute): explain domain verification and Cloudflare proxying (#8581) * docs(compute): explain workspace TXT verification * docs(compute): explain Cloudflare proxy setup and renewal * docs(docs): clarify Cloudflare certificate validation --- apps/docs/content/docs/compute/domains.mdx | 62 +++++++++++++++++----- 1 file changed, 49 insertions(+), 13 deletions(-) diff --git a/apps/docs/content/docs/compute/domains.mdx b/apps/docs/content/docs/compute/domains.mdx index bfbef1e33d5..818d3da6838 100644 --- a/apps/docs/content/docs/compute/domains.mdx +++ b/apps/docs/content/docs/compute/domains.mdx @@ -3,7 +3,7 @@ title: Domains description: Point a custom domain at an app on any branch and the platform verifies DNS and provisions TLS for you. url: /compute/domains metaTitle: Custom domains | Prisma Compute -metaDescription: Add a custom domain to a Prisma Compute app, configure the CNAME record, watch provisioning, and troubleshoot failures. +metaDescription: Connect a custom domain to a Prisma Compute app, verify workspace ownership with TXT, configure routing, and provision TLS. --- Configure custom domains for apps on [production, preview, or staging branches](/compute/branching). Each domain routes to the live deployment of the app on the selected branch. @@ -33,20 +33,54 @@ npx prisma service domain add staging.acme.com --service web --branch staging npx prisma service domain wait staging.acme.com --service web --branch staging ``` -In Console, select the branch and open the app's **Domains** page to add or remove a custom domain. +In Console, select the branch and open the app's **Domains** page. Choose **Add domain**, enter the hostname, and continue to see the CNAME and workspace TXT records. -Registration verifies DNS up front. If the **CNAME** record isn't visible yet, the command fails with a `DOMAIN_DNS_NOT_CONFIGURED` error and prints the record name and value for you to create. Re-running `add` for a hostname that's already attached is safe: it shows the existing domain instead of failing. +Registration verifies ownership before creating a domain or requesting a certificate. If the TXT record is missing, the CLI returns `SERVICE.DOMAIN_OWNERSHIP_REQUIRED` and prints the exact record name and value. Create it, then rerun the suggested command. Re-running `add` for a hostname that's already attached is safe: it shows the existing domain without requiring a new verification step. -### 2. Create CNAME Record +### 2. Add the TXT and CNAME records -Add the printed DNS record, which points at `switchboard.{region}.prisma.build`. +Add the TXT record shown by Console or the CLI. Its value belongs to your workspace. Use the exact value provided; the example below is a placeholder. -Example: -| Type | Name | Value | TTL | -| ----- | --------------- | ------------------------------ | --- | +Also add the routing CNAME, which points at `switchboard.{region}.prisma.build`. If it is not configured yet, `add` returns a DNS error with the CNAME instructions after ownership verification succeeds. + +| Type | Name | Value | TTL | +| --- | --- | --- | --- | +| TXT | `_prisma-verification.shop.acme.com` | `prisma-verification=` | 300 | | CNAME | `shop.acme.com` | `switchboard.cdg.prisma.build` | 300 | -The CLI prints the record name as the full hostname. If your DNS provider expects a relative name, enter just the label (`shop`). +If your provider expects names relative to the `acme.com` zone, use `_prisma-verification.shop` for TXT and `shop` for CNAME. Keep the TXT record: it lets this workspace reconnect the hostname after an app or branch is recreated. Another workspace needs a different value. + +:::note[Cloudflare DNS] + +Set the hostname's **Proxy status** to **DNS only** (gray cloud) while connecting +the domain. A proxied record returns Cloudflare's IP addresses, which prevents +Prisma from verifying your CNAME target. If Prisma detects this, Console and the +CLI show instructions to turn the proxy off and retry. + +After Prisma shows the domain as **Active**, you can turn **Proxied** (orange +cloud) back on to use Cloudflare's CDN. Keep the CNAME target and TXT record in +place, and use **Full (strict)** SSL/TLS mode. + +Prisma issues and renews certificates automatically. Your app does not need a +route or validation file for `/.well-known/acme-challenge/*` because Prisma +responds to these validation requests. + +If you manage the Cloudflare zone, ensure your Cloudflare rules let these requests +reach Prisma. Custom security challenges, caching, redirects, or Workers can +intercept them before they reach Prisma. Add exceptions only for rules that +interfere with this path. Match requests whose URL path starts with +`/.well-known/acme-challenge/`. See [Cloudflare's validation troubleshooting](https://developers.cloudflare.com/ssl/edge-certificates/changing-dcv-method/troubleshooting/) +for rule checks and examples. + +If you remove a domain from Prisma and add it again, switch back to **DNS only** +for verification. The [`service domain retry` command](#troubleshooting) also +requires **DNS only** because it checks DNS again. + +See Cloudflare's [proxy status](https://developers.cloudflare.com/dns/proxy-status/) +and [Full (strict) TLS](https://developers.cloudflare.com/ssl/origin-configuration/ssl-modes/full-strict/) +documentation for these settings. + +::: :::note[What is switchboard?] @@ -56,7 +90,7 @@ Switchboard is the routing layer that sits in front of your Compute app. Switchb ### 3. Re-run `add`, then wait for provisioning -Once the CNAME record has propagated, re-run `service domain add`. This time registration succeeds and TLS provisioning starts. Track it with: +Once both DNS records have propagated, choose **Verify and connect** in Console or rerun the same `service domain add` command, including its branch selector. Registration then starts TLS provisioning. Track it with: ```npm npx prisma service domain wait shop.acme.com --service web @@ -73,10 +107,12 @@ A single check exits non-zero with `DOMAIN_VERIFICATION_TIMEOUT` while the domai ## Remove a domain ```npm -npx prisma service domain remove shop.acme.com --service web +npx prisma service domain delete shop.acme.com --service web ``` -Removing detaches the domain from the app. Pass `--yes` to skip the confirmation prompt. Prisma can't touch your DNS, so the CNAME record stays behind. Delete it at your provider once you no longer need it. +Removing detaches the domain from the app. For a non-interactive run, pass `--confirm shop.acme.com`. Prisma cannot change your DNS. Keep the TXT record if you plan to reconnect the hostname in this workspace; remove both DNS records once you no longer need them. + +Existing connected domains keep serving without adding TXT immediately. A new attachment after removal or branch deletion requires the workspace proof, even when the old CNAME still points at Prisma. ## States @@ -91,7 +127,7 @@ A domain moves through these states: ## Limits -- DNS uses CNAME records only. Apex domains need a DNS provider that supports CNAME-like records (ALIAS, ANAME, or CNAME flattening) at the apex. +- Routing uses a CNAME, and new attachments require a workspace TXT proof. Apex domains need a DNS provider that supports CNAME-like records (ALIAS, ANAME, or CNAME flattening) at the apex. - Wildcard hostnames such as `*.acme.com` are rejected. - Up to 3 custom domains per app. Adding more returns `DOMAIN_QUOTA_EXCEEDED`. - There's no workspace-wide domain list in the CLI.