# Domains

Every deployed copy of the app is served on a hostname. A project on velastack.dev gets one for free under `velastack.app`, and can add its own domains on top.

### velastack.app hostnames

A [linked](/link) project that deploys while logged in — with [`vela login`](/account/login) or `VELA_API_KEY` set — claims a subdomain on its first deploy. The label comes from the project's slug, so a project called `my-shop` becomes `my-shop.velastack.app`; if that label is taken, a short random suffix is added. Every environment of the project is then named from it:

```
my-shop.velastack.app                  production
my-shop--staging.velastack.app         a named target
my-shop--feature-maps.velastack.app    the preview of feature/maps
```

The first `--` separates the project from the environment, which is why a label may not contain two hyphens in a row. Names are flat rather than nested because one certificate covers everything one level under `velastack.app`.

Nothing has to be configured on the server. The deploy prints the URL, and a new name goes live within a minute:

```
Deployed my-shop 20260907T120000Z-8e41

  URL   https://my-shop.velastack.app
  Port  3001 (PocketBase 8091)

my-shop.velastack.app goes live within a minute.
```

A deploy without a link or a key still works exactly as before; it just serves on whatever `--domain` you gave it, and nothing is recorded on velastack.dev.

### Choosing a label

The label is chosen for you, and can be changed on the project's Domains page with **Change subdomain**. Every environment moves to the new name at once, and the old one stops answering within a minute. A label must be:

- 2 to 40 characters of lowercase letters, digits and hyphens
- Not starting or ending with a hyphen, and never containing `--`
- Not a reserved word — infrastructure names like `www`, `api` and `cdn`, sign-in words like `login` and `billing`, mail and DNS names like `smtp` and `ns1`, and environment words like `staging` and `prod`
- Not containing `velastack` or `velabase` anywhere

The field checks availability as you type.

### How managed names are served

Requests to a `velastack.app` name arrive at the edge, which proxies them to your server over HTTPS. Certificates are issued at the edge, so there is nothing to obtain on the server. Two limits come with that path: uploads are capped at 100 MB, and a realtime connection that stays quiet reconnects after about 100 seconds. A domain of your own has neither limit, because it reaches the server directly.

On its first deploy from a linked project, the server is registered with velastack.dev and given an origin name:

```
srv-hqnirofzx4yvhcy.origin.velastack.app
```

That name always points at the server's public address. It is what the edge proxies to, and what your own DNS records alias to. The registration lives in `/etc/vela/origin.json`, readable only by root, and is refreshed on every deploy; if the server's address changes, the origin record follows it.

### Your own domain

There are two ways to attach a domain, and they end up in the same place. The first is the one that has always worked — pass it on deploy, or commit it in `velastack.config.ts`:

```
$ vela deploy --domain www.example.com
```

Production hostnames given this way are recorded on the project's Domains page automatically. The second is to add it there first. **Add domain** asks for the hostname and what it is for:

- **Production** - The hostname production is served on
- **Previews, as a base** - Every preview is also served at `<branch>.` under it, so `preview.example.com` gives `feature-maps.preview.example.com`

Once added, the page shows the DNS record to create. A subdomain is an alias of the server's origin name, so it follows the server if its address ever changes; an apex domain cannot be an alias, so it gets the address instead:

```
www.example.com        CNAME  srv-hqnirofzx4yvhcy.origin.velastack.app
example.com            A      203.0.113.10
*.preview.example.com  CNAME  srv-hqnirofzx4yvhcy.origin.velastack.app
```

**Check DNS** resolves each hostname and confirms it reaches the server. A domain shows as `DNS ok`, `Not reaching the server` or `DNS unchecked`; there is no verification record to add.

A domain added on the dashboard reaches the server on the next deploy of that environment: the deploy picks it up, Caddy on the server obtains its certificate, and traffic to it goes straight to the server. A hostname can belong to one project at a time, and `velastack.app` names cannot be added this way — change the subdomain instead.

### One hostname per environment

An environment is served on one hostname, because SvelteKit's `ORIGIN` is a single host. When an environment has a domain of its own, that domain is primary and the managed name redirects to it, keeping the path and query string:

```
Deployed my-shop 20260907T120000Z-8e41

  URL   https://www.example.com
  Also  https://my-shop.velastack.app (redirects here)
```

Without a domain of its own, the managed name serves. The Domains page shows which is which: **Serving**, **Redirects to** a host, or **Not deployed yet**.

### The Domains page

Each project has a Domains page on velastack.dev with a card per kind of environment:

- **Production** - The managed name, its status, and every production domain with its DNS record
- **Previews** - One row per deployed preview with its hostnames and branch, plus any preview bases
- **Other environments** - Named targets such as `staging`
- **Pointing your own DNS here** - The server's origin name and address, ready to copy

The team's Domains page lists every hostname across all of its projects, read-only. Domains are managed per project.