---
title: Add a domain
description: Give a service a public hostname. DNS and certificates are handled for you.
order: 3
---

A domain is a hostname the edge answers for, routed to one of your services. Ops writes
the DNS record when it holds the zone, and a certificate is issued on the first request.

## In the project file

Declare the domain beside the services, and give it a hostname in the environment it
belongs to:

```ts
export default defineProject({
  services: {
    web: { dockerfile: 'Dockerfile', port: 3000 },
  },
  domains: {
    site: { target: { service: 'web' } },
  },
  $production: {
    domains: { site: { hostname: 'app.rungholt.dk', aliases: ['www.rungholt.dk'] } },
  },
})
```

A domain without a hostname in an environment is not in that environment, so the top level
holds the shape and each `$<environment>` block holds the address. Merge the change to the
default branch and the domain appears under **Domains**.

## In the console

Open **Domains** and choose **Add domain**. Fill in the hostname and the service it routes
to; the port defaults to the service's own. **Create domain** saves it.

## DNS

The domain's page says where it stands:

| state | what it means |
| --- | --- |
| Waiting for DNS | the hostname does not point at ops yet |
| Waiting for CNAME | the same, for a zone that is yours |
| No certificate | DNS is right, the certificate is not issued yet |
| Certificate to *date* | live, with the certificate's expiry |
| Probe down | live, but the probe path does not answer |

When ops holds the zone, it writes the record itself and the first state passes on its
own. When the zone is yours, at another DNS provider, the page shows the record to add
there, with **Copy** to send it to whoever holds the zone. Ops checks again until the record
resolves. Set `zone: 'external'` on a domain to say the zone is not ops's.

## Routing an API path

One site can send a path to a second service, for example a frontend with its API under
`/api/*`:

```ts
domains: {
  site: { target: { service: 'web' }, api: { service: 'api' } },
},
```

`path` defaults to `/api/*`. See [Domains](../resources/domains.md) for every field.
