CLI Reference
Deploy and manage your applications from a terminal or a CI pipeline.
cloady deploys and manages your applications from a terminal. It calls the
same REST API the dashboard uses, so anything you script behaves
exactly like clicking through the UI.
Install
npm install -g cloadyRequires Node 20+. Verify with:
cloady --versionAuthentication
cloady login with no arguments opens your browser, shows a code to confirm,
and stores the token it hands back:
cloady login
# Confirm this code matches: WXYZ-1234
# logged in as you@example.comAdd --scope read, --scope deploy or --scope full (the default) to limit
what that token may do.
To use a token you made yourself, create one in the dashboard under
Account → API tokens — the value (cldy_…) is shown once — and pass it as
an argument:
cloady login cldy_…Either way the token is stored in ~/.config/cloady/config.json (mode 0600;
honors $XDG_CONFIG_HOME). cloady logout removes it.
Token resolution order, first match wins:
--token <token>flagCLOADY_TOKENenvironment variable- The stored config file
CI tip: skip login entirely and set CLOADY_TOKEN in the job environment.
Global options
Every command accepts:
| Flag | Effect |
|---|---|
--token <token> | Use this API token for the single invocation |
--api-url <url> | Point at a different Cloady API; resolution mirrors the token: flag → CLOADY_CONTROL_PLANE_URL → config |
--json | Print the raw API response as JSON instead of the human-readable line format — the mode to use in scripts |
Errors print to stderr as error: <code>: <message> and exit non-zero, so
&& chains and CI steps fail correctly. The ones you'll actually hit:
| Code | What it means | What to do |
|---|---|---|
payment_required | The app would take the workspace past its free allowance and there is no card on file, or it was declined | Add a card under workspace Settings → Billing, or make the app smaller |
region_required | An app with that id exists in more than one region | Pass --region |
not_found | No app with that id in that workspace and environment | Check cloady apps <workspace> |
Deploy from a repository
cloady deploy is the only create command; --type says where the code comes
from (git, upload or catalog).
cloady deploy github.com/your-org/your-repo --type gitWhat happens with no other flags:
- Workspace — if you have exactly one, it's used. Several → an interactive picker. None → the CLI walks you through creating one right there (name and id; a new workspace costs nothing).
- Region — where most of your apps already run, otherwise the first region that's ready. Picking a region just chooses where this app runs.
- Name — the repository name.
- Environment —
production.
The build runs on Cloady (your stack is detected, or your Dockerfile is used
when the repo has one), and the app answers on a URL like
shop-k7q2v9ze-acme.cloady.io — your app's name, a short code, and your
workspace's name, with HTTPS set up for you. Preview and development apps put
the environment in the URL: shop-k7q2v9ze-acme.preview.cloady.io.
The command returns as soon as the deploy starts, printing the app id, its status and its URL; the build keeps running afterwards. Private repositories work once the workspace has GitHub connected (Settings → Integrations).
Flags, for every source type:
| Flag | Meaning | Default |
|---|---|---|
--type <type> | git · upload · catalog | upload |
-w, --workspace <id> | Target workspace | auto-detected |
--region <region> | Where the app runs | auto-detected |
--name <name> | Display name; the app id and its URL follow it | repo, folder or catalog name |
--env <env> | production · preview · development | production |
--port <port> | Port your server listens on (ignored when your repo brings its own compose file) | 3000 |
--value <key=value> | Set an environment variable on the new app; repeatable | — |
--branch <branch> | Git branch to build (--type git) | repo default |
--subdir <dir> | Build a subdirectory, for monorepos (--type git) | repo root |
cloady deploy github.com/acme/api --type git --name api --env preview --branch develop --port 8080Each app runs in one region and one environment, and an app's name is unique within a workspace and environment.
Deploy a local folder
With no --type, cloady deploy zips the current directory and uploads it —
no git remote needed:
cloady deploy # the current folder
cloady deploy ./services/api # some other folder.git, node_modules, .next, dist, .turbo, .venv, venv,
__pycache__ and .DS_Store are skipped. The CLI prints how many files it
sent, then builds exactly as it does for a repository. The app is named after
the folder unless you pass --name.
Install a catalog application
cloady deploy <applicationId> --type catalogapplicationId is the catalog id (wordpress, postgres, n8n, …) — the
same ids the dashboard's New Application picker shows. Workspace and region
are resolved the same way as for a repository, and all the flags above apply.
Use --value for the settings the application asks for; anything you leave out
gets its default or a generated secret.
cloady deploy wordpress --type catalog -w acme --region eu1 --name blog
cloady deploy postgres --type catalog -w acme --region eu1 --value POSTGRES_DB=appInspect
cloady whoami # the authenticated user
cloady workspaces # your workspaces (alias: ws)
cloady regions # every region, with whether it's ready
cloady apps <workspace> # apps in a workspace
cloady apps <workspace> --env production --region eu1apps prints one line per app: id, status, region, environment, name. Add
--json for the full objects — endpoints, services, resource limits, source.
Lifecycle
All of these take <workspace> <appId> plus --env (default production) and
--region. Region can be omitted when the app id is unambiguous — if the same
id exists in several regions you'll get a region_required error asking you to
pass it.
cloady start acme blog # start a stopped app
cloady stop acme blog # stop it; its data is kept
cloady redeploy acme blog # rebuild the latest code and roll the containers
cloady restart acme blog # alias for redeploy
cloady delete acme blog # delete the app AND its datadelete is immediate and unprompted, and it deletes the app's data
permanently. There is no undo. To change an app's name or its URL, rename it
in the dashboard — the address follows the name, so you never delete an app to
rename it.
Run a command in a container
cloady exec <workspace> <appId> --component <name> -- <command…>Runs a one-off command in a running container and prints its output. The
command's exit code becomes the CLI's exit code (124 if it times out), and
piped stdin is forwarded.
| Flag | Meaning |
|---|---|
--component <name> | Required. Which service of the app to run in (e.g. wordpress, db) |
--cwd <dir> | Working directory (default: the container's own) |
--timeout <seconds> | Give up after this long (default 30, max 300) |
--env <env> / --region <region> | As above |
cloady exec acme blog --component wordpress -- wp plugin list
cloady exec acme db --component postgres -- psql -U app -c 'select 1'
echo 'select count(*) from users;' | cloady exec acme db --component postgres -- psql -U appThe command runs through /bin/sh -c, so quote pipes and globs if you want
them evaluated inside the container. Long output is truncated to its tail, with
a note on stderr. Two errors are specific to exec: unknown_component means
the app has no service by that name (check the app's page in the dashboard),
and no_pod means nothing is running — start the app first.
Scripting recipes
# wait until an app reports running
until cloady apps acme --json | jq -e '.[] | select(.slug=="blog" and .status=="running")' >/dev/null; do sleep 5; done
# redeploy from CI on every push to main
CLOADY_TOKEN=$CI_SECRET_TOKEN cloady redeploy acme api
# list every app across all workspaces
for ws in $(cloady ws --json | jq -r '.[].slug'); do cloady apps "$ws"; doneFor anything the CLI doesn't cover, drop down to the REST API — same token, same base URL.