# Deploying a website

Take a site from your project to a live URL — and connect your own domain — in a few minutes.

Canonical page: https://app.teachervoiceai.com/docs/guides/deploying-a-website

Machine can deploy a website straight from your project: it builds your source,
ships it to a global edge, and gives you a live URL. This guide walks the whole
path, including connecting a custom domain.

For the underlying model, see [Apps](/docs/concepts/apps); for every field, see
the [Manifest reference](/docs/reference/manifest#apps).

## Deploy your first app

### Declare the app

Add an `[[apps]]` entry to your project's `machine.toml`. At minimum, point it at
the source and tell it how to build:

```toml
[[apps]]
slug = "marketing"
name = "Marketing site"

[apps.source]
type      = "git"        # deploy from this project's repo
branch    = "main"
root_path = "apps/site"  # the folder to build, if not the repo root

[apps.build]
command = "pnpm build"
out_dir = "dist"
```

Prefer the dashboard? The **Apps** tab has a form that writes the same entry and
commits it for you.

### Deploy

Save the manifest. Machine's reconcile loop notices the new entry and deploys it
automatically — or hit **Deploy** in the Apps tab to ship immediately.

Watch the status move through `building` → `deploying` → `active`. If a build
fails, the card shows the error and a link to the logs.

### Open your live URL

Once the deploy is `active`, the card shows a stable Vercel URL —
`your-app-yourteam.vercel.app`. Click it; your site is live. Share it as-is, or
connect your own domain next.

## Connect a custom domain

### Add the domain

List the domains you own under `domains` (or add them in the Apps tab):

```toml
[[apps]]
slug    = "marketing"
domains = ["example.com", "www.example.com"]
```

Machine attaches each domain to the deployment on the next deploy.

### Add the DNS records

Until DNS points at the provider, the app's card shows a **DNS records** panel
with the exact records to add — read live from the provider:

| Type    | Name  | Value                              |
| ------- | ----- | ---------------------------------- |
| `A`     | `@`   | the provider's IP addresses        |
| `CNAME` | `www` | the provider's CNAME target        |
| `TXT`   | …     | an ownership record, when required |

Add these at your DNS provider (the registrar or DNS host for the domain):

- **Apex domains** like `example.com` → the `A` records.
- **Subdomains** like `www.example.com` or `docs.example.com` → the `CNAME`.

Use the copy button next to each value so you paste it exactly.

### Wait for it to verify

DNS changes can take anywhere from a minute to a few hours to propagate. Machine
re-checks automatically; once the records resolve, the domain verifies and starts
serving your site — no redeploy needed. The DNS panel disappears when the domain
is live.

> **Warn**
> **"Invalid configuration" / domain not serving?** That almost always means the
> DNS records haven't propagated yet, or they don't exactly match the panel.
> Double-check the `Type`, `Name`, and `Value` against what's shown, remove any
> conflicting old `A`/`CNAME` records for the same name, and give it time.

## Redeploy and roll forward

Apps redeploy automatically whenever their manifest entry changes — a new commit
to the branch, an edit to the build command, a new env var. To redeploy without
changing anything, use **Redeploy** on the card. The current version keeps
serving until the new build is ready.

## Multiple apps

A project can declare as many `[[apps]]` entries as you need — a marketing site,
a docs site, and a dashboard side by side, each with its own source, build,
domains, and environment. They appear together in the Apps tab.

---

**Related:** [Apps concept](/docs/concepts/apps) · [Manifest reference](/docs/reference/manifest#apps) · [Managing secrets](/docs/guides/managing-secrets) for values your build needs.
