First deploy
From an empty project to a running, routed service.
This walks from nothing to a service on a real URL using the
otterdeploy CLI. It assumes you have a control plane already —
if not, install one first.
1. Install the CLI
npm install -g @otterdeploy/cliRuns on Node ≥ 20 or Bun.
2. Sign in
otterdeploy login https://deploy.example.comThis opens your browser to approve the device — the same flow gh and vercel
use. The token is stored at ~/.config/otterdeploy/config.json (mode 0600).
For CI, set OTTERDEPLOY_URL and OTTERDEPLOY_TOKEN instead of logging in, and
mint the token with otterdeploy tokens create.
If you belong to more than one organisation, pick the active one:
otterdeploy org list
otterdeploy org use acme3. Scaffold and deploy
up links (or creates) the project, writes a config file, offers a first
service, and deploys — all in one step:
cd my-app
otterdeploy upPrefer explicit steps?
otterdeploy init # write the config
otterdeploy add service web --image nginx:latest --port 80
otterdeploy deploy # reconcileTo build from the repo instead of pulling an image, connect a GitHub App installation in the dashboard first, then bind the service to a repo and branch — see services.
4. Watch it converge
Deploy and block until every resource is healthy. Non-zero exit on failure, so it works as a CI gate:
otterdeploy deploy --waitStream logs, tail a build, or check deployment history:
otterdeploy logs web
otterdeploy logs web --build
otterdeploy deployments web5. Put it on a domain
Point a DNS record at the server, then attach the domain:
otterdeploy domains add app.example.com --service web
otterdeploy domains list --service webThe Caddy edge picks it up and requests a certificate. Both the DNS and certificate states are reported honestly — see domains and TLS for what each state means and what to do about it.
6. Add a database
otterdeploy add database postgres --engine postgresThen reference it from the service rather than copying a connection string:
{ "DATABASE_URL": "${database:postgres.DATABASE_URL}" }The value is resolved at deploy time. See environment variables.