---
title: "Attach domains to a revision"
method: PUT
path: "/v2/revisions/{revision}/domains"
tags: ["revisions", "domains"]
---

# Attach domains to a revision

`PUT /v2/revisions/{revision}/domains`

Bind domains to this revision. Bindings are scoped to this revision only — other revisions keep their existing routing.

Each hostname must fall under a domain your organization has already verified, following the same rule and `{variable}` template syntax as the `domains` field on `POST /apps/{app}/deploy` (see its `production`/`preview` documentation).

You can also (re-)attach this revision to the app's **default** managed domains post-deployment by listing the default-alias template — the same value `POST /apps/{app}/deploy` accepts (e.g. `{deno.app.slug}.<org>.<managed-domain>` under `production`, or the per-revision `{deno.app.slug}-{deno.revision.id}.…` under `preview`). Listing it sets the timeline label on the revision rather than pinning a custom hostname: the default production host floats to the **latest** revision attached this way, while each revision keeps its own default preview host.

Binding the same hostname to this revision again is a no-op. Use `DELETE /revisions/{revision}/domains/{hostname}` to remove a binding.

A hostname always resolves to **exactly one** revision. Binding is additive: attaching a hostname to a revision never detaches it from any revision it is already bound to. When a hostname is bound to several revisions, the **most recently created revision wins**.

Because the newest bound revision always wins, moving a hostname *forward* to a newer revision is just an attach: bind it to the newer revision and that revision immediately takes over routing — you do not detach the old one. Moving a hostname *back* to an older revision is different: re-attaching the older revision has no effect while a newer revision is still bound, so you must explicitly `DELETE` the binding on every newer revision. Detaching the currently-winning revision falls back to the next most recently created revision that is still bound; the hostname only stops routing once its last binding is removed.

Returns `204 No Content` on success.

## Path parameters

- `revision` string, required

## Request body

- object
  - `production` string[] — Hostnames to bind to this revision under the production timeline. Every entry must fall under a domain your organization has already verified — either the verified domain itself (an apex hostname such as `my-domain.com` bound against the verified `my-domain.com`) or a subdomain of a verified wildcard domain (such as `my-app.my-org.deno.net` bound against the verified `*.my-org.deno.net`). A hostname that does not fall under any verified domain is rejected. The leading label of a subdomain may contain `{variable}` template expressions so the hostname resolves to a distinct value per revision. Template variables may appear only in the first label, may be combined with static text and with each other (e.g. `pr-{deno.revision.id}` or `{deno.app.slug}--{deno.revision.id}`), and must not contain a dot. The available variables are `{deno.revision.id}`, `{deno.app.slug}` (or its opaque equivalent `{deno.app.id}`), and `{deno.organization.id}`. A hostname always resolves to exactly one revision: binding is additive, but when a hostname is bound to multiple revisions the most recently created revision wins. To roll a hostname back to an older revision you must explicitly detach the newer revision(s) via `DELETE /revisions/{revision}/domains/{hostname}`.
  - `preview` string[] — Hostnames to bind to this revision under the preview timeline. Every entry must fall under a domain your organization has already verified — either the verified domain itself (an apex hostname such as `my-domain.com` bound against the verified `my-domain.com`) or a subdomain of a verified wildcard domain (such as `my-app.my-org.deno.net` bound against the verified `*.my-org.deno.net`). A hostname that does not fall under any verified domain is rejected. The leading label of a subdomain may contain `{variable}` template expressions so the hostname resolves to a distinct value per revision. Template variables may appear only in the first label, may be combined with static text and with each other (e.g. `pr-{deno.revision.id}` or `{deno.app.slug}--{deno.revision.id}`), and must not contain a dot. The available variables are `{deno.revision.id}`, `{deno.app.slug}` (or its opaque equivalent `{deno.app.id}`), and `{deno.organization.id}`. A hostname always resolves to exactly one revision: binding is additive, but when a hostname is bound to multiple revisions the most recently created revision wins. To roll a hostname back to an older revision you must explicitly detach the newer revision(s) via `DELETE /revisions/{revision}/domains/{hostname}`.

## Response `204`

OK

---

[API](https://skmtc.net/deno/apis/deploy.md) · [All operations](https://skmtc.net/deno/apis/deploy/llms.txt) · [OpenAPI document](https://skmtc-service-staging.skmtc.workers.dev/v1/apis/deno/deploy/versions/5a56038d108e/schema)
