> ## Documentation Index
> Fetch the complete documentation index at: https://docs.slipway.sh/llms.txt
> Use this file to discover all available pages before exploring further.

# Custom domains

> Serve previews under your own parent zone instead of the platform's apps domain.

By default, every public service is served at `<env-name>-<service>-<id>.<platform-apps-domain>` — for example `test-api-3f9a2c1b.app.slipway.sh`. The `<id>` is a short, stable identifier derived from the environment-instance (every service of one instance shares it, and it survives redeploys). If you'd rather serve previews under your own zone — `<env-name>-<service>-<id>.preview.acme.com`, for example — claim a custom domain in your org.

Custom domains are managed at the org level. Your `slipway.yaml` references a verified zone by name in `ports[].domain`; the zone itself is claimed and verified in the UI. Every plan includes unlimited custom domains.

## Claim a domain

Open **Domains** in the sidebar, click **Add domain**, and enter the parent zone you want to serve previews under (e.g. `preview.acme.com`). Slipway gives you a **CNAME target** — copy it into your DNS provider as a wildcard record:

```
*.preview.acme.com   CNAME   <target-from-slipway>
```

Back in slipway, click **Verify**. Slipway resolves the CNAME from the public internet to confirm it points where it should.

Once verified, the domain is available to every repo in the org.

## Use it in a spec

Add `domain:` to the public port:

```yaml theme={"system"}
services:
  web:
    build: { context: . }
    ports:
      - { port: 3000, public: true, domain: preview.acme.com }
    healthcheck:
      readiness: { http: { path: /healthz, port: 3000 } }
```

Deployed URLs become (with `<id>` the environment-instance's stable identifier):

* **PR previews**: `myenv-web-3f9a2c1b.preview.acme.com`
* **Default-branch / manual**: `myenv-web-9f8e7d6c.preview.acme.com`

If the `domain:` in a spec doesn't match a verified domain for the org, the deploy **fails** at the deploy phase with a clear error. Slipway won't issue a certificate for a zone the org hasn't proven it owns.

## Set it on a whole environment

Instead of repeating `domain:` in every service's spec, pick a verified zone on the **environment** itself — either in the composer's **Settings** step (the **Domain** dropdown, when creating the environment) or later on the environment detail page under **Settings → General → Custom domain**. Every public service in that environment is then served under it by default — no spec change needed. Both dropdowns list only your org's verified zones; leave them on the default for the platform apps domain.

Precedence, highest first:

1. A per-port `domain:` in the spec (overrides everything for that port).
2. The environment's custom domain (the default for the whole env).
3. The platform apps domain.

Changing an environment's custom domain advises a **redeploy** — existing healthy deployments keep their current URLs until they're redeployed onto the new zone.

## Pin a subdomain per service

The computed host always carries the stable `<id>` hash so URLs never collide. For the **permanent deployment** of a service, under a verified custom domain, you can drop the hash and pick the subdomain yourself: serve `api` at a clean `api.acme.com` instead of `myenv-api-3f9a2c1b.acme.com`.

Set it per public service:

* **On an existing environment**, open **Settings → Domains**. Pick the custom domain at the top, then each public service gets a subdomain field below it. The **Composition** tab shows the resulting host read-only.
* **In the composer**, on a component card, once you've chosen a custom domain and enabled the permanent deployment, each public service shows a subdomain field next to its URL preview.

Rules:

* The value is a single label (for example `api`, `app`, `dashboard`). It sits directly under the environment's verified zone, so `api` becomes `api.acme.com`.
* Each label must be unique within a zone across your org. Two services can't both claim `api.acme.com`.
* Leave it blank to fall back to the computed `<env>-<service>-<id>.<zone>` host.

Only the permanent deployment uses the clean host. PR previews and one-off runs keep the computed `<id>` host so their throwaway copies never collide. A change takes effect on the next deploy, so the environment shows a **Stale** marker until you redeploy.

## TLS

TLS certificates for every preview hostname are provisioned and renewed automatically. You don't manage certificates yourself — there's nothing to install, rotate, or keep an eye on.

## Multiple domains per org

You can claim as many parent zones as you need. Different repos (or different services in the same repo) can use different zones.

## Removing a domain

Removing a verified domain from **Settings → Domains** stops new deployments from using it, but doesn't tear down existing certificates or previews already running on it. Tear down any healthy deployments still using the domain before removing it if you want a clean cut.
