---
url: /guide/getting-started.md
description: >-
  Install the duploy CLI, sign in, describe your app in duploy.toml and ship the
  first deploy.
---

# Getting started

Duploy runs your code on our nodes. You describe the project in one file,
`duploy.toml`, at the root of your repository; Duploy builds it, rolls it out
and keeps it running. There are no servers to install.

## 1. Install the CLI

```bash
curl -fsSL https://panel.duploy.dev/cli/install.sh | sh
```

The script installs `duploy` and registers shell completion for your shell.
Options go in as environment variables:

| Variable | Effect |
|---|---|
| `DUPLOY_VERSION` | Install a specific version instead of the latest |
| `DUPLOY_INSTALL_DIR` | Install somewhere other than `~/.local/bin` |
| `DUPLOY_NO_COMPLETIONS=1` | Skip shell completion |

Completion is dynamic: pressing Tab after `-p`, `logs`, `db` or `tunnel` offers
the real names of your projects, services and databases.

## 2. Sign in

```bash
duploy login        # opens the panel in your browser to approve the device
duploy whoami
duploy use acme     # pick an org; `duploy use acme/shop` picks a project too
```

`duploy login --no-browser` prints the URL instead of opening it. In CI, use an
access token instead of a login: see [CI and automation](/guide/ci).

## 3. Create a project and connect the repository

Create a project in the [panel](https://panel.duploy.dev) and connect its
GitHub repository. From then on every push to the linked branch is picked up:
Duploy reads `duploy.toml`, rebuilds the services whose files changed and
deploys them.

Link your working copy to the project so the CLI knows where you are:

```bash
cd ~/code/shop
duploy link shop    # writes a .duploy file; `duploy unlink` removes it
```

The CLI resolves the project in this order: `-o`/`-p` flags, then the nearest
`.duploy` file, then `duploy use`.

## 4. Write duploy.toml

A web service built from the repository's Dockerfile, plus a Postgres
database:

```toml
version = 1

[services.web]
source = { path = ".", dockerfile = "Dockerfile" }
port = 8080
domains = [{ host = "shop.example.com" }]
health = { http = "/healthz" }

[services.web.env]
DATABASE_URL = { from_database = "db" }
SESSION_KEY = { secret = true }

[databases.db]
engine = "postgres"
version = "18"
backup = { schedule = "0 3 * * *", retain = 7 }
```

* `port` is where your app listens inside the container. It also reaches the
  app as `$PORT`.
* `from_database` injects the connection URL of the managed database; the
  password never appears in the file.
* `secret = true` declares a secret. The value is written separately and is
  never shown again.

The full key list is in the [duploy.toml reference](/reference/duploy-toml).

## 5. Set secrets and deploy

```bash
duploy secret set web SESSION_KEY=$(openssl rand -hex 32)
git add duploy.toml && git commit -m "deploy on duploy" && git push
```

The push starts a build and then a deploy. To follow along, or to trigger one
by hand:

```bash
duploy deploy web          # streams the log until the deploy finishes
duploy services            # status, replicas, last build
duploy logs web -f         # the container log
```

## 6. Point DNS at Duploy

Your domain gets a certificate from Let's Encrypt as soon as its DNS points at
Duploy. `duploy project ingress` shows what to point it at. See
[Domains and TLS](/guide/domains).

## Next

* [How Duploy works](/guide/how-it-works): builds, deploys and the config
  model
* [Services](/guide/services): web services, workers, sources, health checks
* [Managed databases](/guide/databases): backups, restore, import
