Deploy apps to your own servers from the command line. Zero DevOps, full control.
The DollarDeploy CLI (ddc) lets you manage servers, deploy applications, and control your infrastructure — all from the terminal. Designed for CI/CD pipelines, AI agents, and developers who prefer the command line.
npm install -g @dollardeploy/cliOr use npx:
npx @dollardeploy/cli help- Sign in at dollardeploy.com
- Go to Settings → API Keys
- Click Create API Key and copy it
# Interactive
ddc auth
# Non-interactive
ddc auth --api-key <your-api-key>Your API key is saved to ~/.dollardeploy/auth and can be overridden with the --api-key flag or DOLLARDEPLOY_API_KEY environment variable.
# Deploy the git repo in the current folder (detects repo, env, shows overview)
ddc deploy
# Deploy from GitHub to an existing host
ddc deploy --url https://github.com/your-org/your-app --hostId <host-id>
# Deploy and auto-create a host
ddc deploy --url https://github.com/your-org/your-app --create-host
# Deploy from a template
ddc deploy --template nextjs-boilerplate --hostId <host-id>A host goes through a few stages: create → provision → prepare → (deploy apps) → deprovision / destroy.
ddc host create --provider ... runs all of the setup steps for you in one call. The individual commands exist for when you want to run a stage on its own — for example, provisioning a server for a host you created earlier, or re-preparing a host without touching the VM.
# 1. Create the host record and provision a server in one step
ddc host create --name my-server --provider hetzner
# ↳ creates the host, provisions the VM, tests SSH, installs services, prepares it
# --- or run the stages yourself ---
# 1a. Create just the host record (no server yet)
ddc host create --name my-server
# → prints the new host id, status: draft
# 1b. Provision a server for that host
ddc host provision <host-id> --provider hetzner
# → status: active, IP assigned
# 1c. Verify SSH connectivity
ddc host test <host-id>
# 1d. Prepare the host for deployments (installs Docker, configures the box)
ddc host prepare <host-id>
# 2. Deploy apps to it
ddc deploy --url https://github.com/org/repo --hostId <host-id>
# 3. When you're done, tear it down
ddc host destroy <host-id> # deprovision the VM AND delete the host record
# or, to keep the host record but delete the server:
ddc host deprovision <host-id>
# or, to stop managing it without deleting the server:
ddc host remove <host-id>Tip: run
ddc host listat any point to see each host'sstatusandip. Long-running stages (provision, prepare, deploy) print progress; add--jsonfor machine-readable output.
Save your API key for future commands.
ddc auth # Interactive prompt
ddc auth --api-key <key> # Non-interactiveAPI key resolution order: --api-key flag > DOLLARDEPLOY_API_KEY env var > ~/.dollardeploy/auth file.
Show the current user, the tenant the API key belongs to, and your roles in that tenant (e.g. admin, or scoped entries like write=project:<id>). Commands your roles don't allow fail with 403.
ddc user
ddc auth status # aliasList all hosts in your account.
ddc host list
ddc host list --status active
ddc host list --json # Machine-readable outputShow a single host. Plain-text output lists every host field except the noisy objects (health, apps, project) and includes the provision config formatted inline. Use --json or --all for the full host object.
ddc host get <host-id>
ddc host get <host-id> --json # Full host object incl. provision
ddc host get <host-id> --all # Full host object as key: valueCreate and provision a new host. You need to set the integration with your cloud provider first in the DollarDeploy Settings => Integrations.
# Just create a host entry
ddc host create --name my-server
# Create a host on Hetzner
ddc host create --name my-server --provider hetzner --type cpx31 --region fsn1
# Create a host on DigitalOcean
ddc host create --name my-server --provider do --type s-2vcpu-4gb --region fra1
# Create a host on Verda Cloud (formerly DataCrunch)
ddc host create --name my-server --provider verda --type CPU.4V.16G --region FIN-01
# Create a host with Docker and PostgreSQL
ddc host create --name my-server --services docker,postgres| Option | Description | Default |
|---|---|---|
--name |
Host name | auto-generated |
--provider |
Cloud provider: hetzner, do, verda |
hetzner |
--type |
Instance type | cax11 |
--region |
Provider region | fsn1 |
--image |
OS image | ubuntu-24.04 |
--services |
Comma-separated services to install | docker |
--skip-prepare |
Skip host preparation step | false |
--timeout |
Timeout in milliseconds | 600000 |
Update settings of an existing host (alias: ddc host modify). Only the flags you pass are changed. --env values are merged into the host's existing env vars, and --add-hostname / --remove-hostname edit the current hostname list.
ddc host update <host-id> --name web-1 --swap 4096
ddc host update <host-id> --add-hostname api.example.com,www.example.com
ddc host update <host-id> --env POSTGRES_VERSION=17 --env POSTGRES_DATABASES=app| Option | Description |
|---|---|
--name |
Host name (min 3 chars) |
--description |
Host description |
--ip |
IP address or DNS name used for SSH |
--username |
SSH username |
--sshKeyId |
SSH key to use (see ddc ssh list) |
--swap |
Swap size in MB, applied on the next host prepare |
--projectId |
Move the host to a project |
--backupSchedule |
Backup schedule (cron expression) |
--hostnames |
Replace all hostnames (comma-separated) |
--add-hostname |
Add hostnames (comma-separated) |
--remove-hostname |
Remove hostnames (comma-separated) |
--env |
NAME=VALUE host env var, merged, repeatable |
Requires the write role on the host (or maintain/admin).
Provision (or reprovision) a server for an existing host. Pass provider flags to save the provider config before provisioning; omit them to provision using the config already saved on the host.
# Provision using flags
ddc host provision <host-id> --provider hetzner --type cax11 --region fsn1
# Provision using the host's already-saved provider config
ddc host provision <host-id>| Option | Description | Default |
|---|---|---|
--provider |
Save this provider before provisioning | — |
--type |
Instance type (uses provider default if omitted) | provider based |
--region |
Provider region (uses provider default if omitted) | provider based |
--image |
OS image (uses provider default if omitted) | provider based |
--timeout |
Timeout in milliseconds | 600000 |
Not sure which
--type,--region, or--imagevalues are valid? Runddc provision --provider <p>to list everything the provider supports.
Test the SSH connection to a host.
ddc host test <host-id>Prepare a host for deployment. This will install the necessary services and configure the host for deployment.
ddc host prepare <host-id>Manage the services (Docker, PostgreSQL, etc.) installed on a host.
# List installed services
ddc host service list <host-id>
# Show a single service (--all for the full object)
ddc host service get <host-id> <service-id>
# Install a service
ddc host service add <host-id> docker
# Remove a service
ddc host service remove <host-id> <service-id>Deprovision the server (removes the VM from your cloud provider) but keep the host record in DollarDeploy, so you can provision it again later.
ddc host deprovision <host-id>
ddc host deprovision <host-id> --yes # Skip confirmationDeprovision and permanently delete a host. This removes the VM from your cloud provider and deletes the host record along with all apps on it.
ddc host destroy <host-id>
ddc host destroy <host-id> --yes # DANGEROUS: Skip confirmationRemove a host from DollarDeploy without deprovisioning. The server continues running but is no longer managed.
ddc host remove <host-id>
ddc host remove <host-id> --yes # DANGEROUS: Skip confirmationList the regions, instance types, and images a provider supports, queried live from the provider API. Use it to discover valid --type, --region, and --image values before running ddc host create or ddc host provision.
The provider must be connected first (Settings → Integrations in the dashboard). --provider is required; all other flags narrow down the instance type list.
# List everything available for a provider
ddc provision --provider hetzner
# Only show types available in a region
ddc provision --provider hetzner --region fsn1
# Only show ARM types with at least 4 vCPUs and 8 GB memory
ddc provision --provider hetzner --arch arm64 --cpu 4 --memory 8192
# Full config as JSON (regions, types, images, defaults)
ddc provision --provider do --jsonExample output:
Provider: hetzner default region: fsn1 default image: ubuntu-24.04 default arch: arm64
Regions:
id label
---- ------------
fsn1 Falkenstein
nbg1 Nuremberg
hel1 Helsinki
...
Instance types:
type cpu memoryGB diskGB arch gpu regions
----- --- -------- ------ ----- --- -------
cax11 2 4 40 arm64 all
cax21 4 8 80 arm64 all
...
Images:
image
------------
ubuntu-24.04
debian-12
...
| Option | Description | Default |
|---|---|---|
--provider |
Required. Cloud provider: hetzner, do, verda |
— |
--region |
Filter instance types available in a region | — |
--type |
Show details for a specific instance type | — |
--arch |
Filter by architecture (e.g. arm64, amd64) |
— |
--cpu |
Filter to types with at least N vCPUs | — |
--memory |
Filter to types with at least N MB of memory | — |
--disk |
Filter to types with at least N GB of disk | — |
Deploy an application to a host. Supports GitHub repos, templates, and redeployment of existing apps.
Also available as ddc app deploy.
# Deploy the git repo in the current folder (no arguments)
ddc deploy
# Deploy from GitHub (will redeploy existing app if URL matches)
ddc deploy --url https://github.com/org/repo --hostId <host-id>
# Deploy with a new host
ddc deploy --url https://github.com/org/repo --create-host
# Deploy a template
ddc deploy --template twenty-crm --hostId <host-id>
# Redeploy an existing app
ddc deploy --appId <app-id>
# Deploy with environment variables
ddc deploy --url https://github.com/org/repo --hostId <host-id> --env:DATABASE_URL postgres://...
# Deploy with app property overrides
ddc deploy --url https://github.com/org/repo --hostId <host-id> --set:mainPort 8080Run ddc deploy with no --url, --template, or --appId inside a git repository and it deploys the current folder, Vercel-style:
- Detects the repository from the
originremote (falling back to the first remote) and normalizes it to anhttps://github.com/org/repoURL. - Uses the current branch as the deploy source branch (override with
--sourceBranch). - Warns if the working tree is dirty or has commits that are not pushed - the deploy builds from the remote, so only committed and pushed work ships.
- Reads environment variables from the first match of
.env.production,.env.prod,.env.production.local,.env.local. Keys found only in.env.examplebecome empty placeholders to fill in at dollardeploy.com. - Shows a confirmation overview (repository, branch, target host, env variable names with values hidden, and placeholders that still need values), then asks you to confirm. Values are never printed to the terminal, and the env name list is capped at 5 names with a
+ N moresummary. Use--yesto skip the prompt (required in non-interactive/CI environments), and--path <dir>to deploy a different folder. - App already exists? If the repository matches an existing app, its settings and env are left untouched - you are only asked to trigger a redeploy of the existing app. If that app has no server selected yet, nothing is deployed - you get a link to pick one at dollardeploy.com.
- No server yet? If no active host exists, it creates an app entry with no server selected and prints a link to pick one at dollardeploy.com.
# Deploy the current folder, skip the confirmation (CI)
ddc deploy --yes
# Deploy a specific folder on a chosen host
ddc deploy --path ./services/api --hostId <host-id>The deploy command is smart about redeployment — if you deploy the same GitHub URL to the same host, it will detect the existing app and redeploy it instead of creating a duplicate.
| Option | Description |
|---|---|
| (no url/template) | Deploy the git repo in the current folder |
--path |
Folder to deploy (default: current directory) |
--yes |
Skip the local-deploy confirmation prompt |
--url |
GitHub repository URL |
--template |
Template ID to deploy |
--appId |
Existing app ID to redeploy |
--hostId |
Target host ID |
--create-host |
Create a new host for deployment |
--name |
App name |
--sourceBranch |
Branch to deploy from (default: current branch) |
--env NAME=VALUE |
Set environment variable |
--set:<key> |
Set app property (mainPort, env:PROPERTY_NAME, etc.) |
--provider |
Provider for --create-host |
--type |
Instance type for --create-host |
--region |
Region for --create-host |
--services |
Services for --create-host |
--timeout |
Timeout in milliseconds (default: 600000) |
Build an app, optionally deploying it after build.
Also available as ddc app build.
ddc build <app-id>
ddc build <app-id> --deploy| Option | Description |
|---|---|
--deploy |
Deploy after building |
--timeout |
Timeout in milliseconds (default: 600000) |
List all apps in your account.
ddc app list
ddc app list --jsonShow a single app. Plain-text output lists every app field except the noisy objects (host, project); env is formatted inline. Use --fields to pick specific columns, or --json/--all for the full app object.
ddc app get <app-id>
ddc app get <app-id> --json # Full app object incl. env
ddc app get <app-id> --fields id,name,status,hostname
ddc app get <app-id> --all # Full app object as key: valueUndeploy an app from its host. By default the app is also deleted; use --keep to undeploy but keep the app configuration for later.
ddc app remove <app-id> # Undeploy and delete the app
ddc app remove <app-id> --keep # Undeploy but keep the configuration
ddc app remove <app-id> --yes # Skip confirmation| Option | Description |
|---|---|
--keep |
Keep the app configuration (undeploy only) |
--yes, --force |
Skip confirmation prompt |
--timeout |
Timeout in milliseconds (default: 600000) |
List all templates.
ddc template list
ddc template list <search>
ddc template list --jsonAdd an SSH public key to your DollarDeploy account.
ddc ssh add ${HOME}/.ssh/id_rsa --name my-key| Option | Description |
|---|---|
--name |
Key name (default: cli-added-key) |
List all SSH keys in your account.
ddc ssh list
ddc ssh list --name my-keyDelete an SSH key from your account.
ddc ssh remove <key-id>
ddc ssh remove <key-id> --yes # Skip confirmationInspect and control the background tasks that run provisioning, builds, and deployments.
ddc task list # List recent tasks
ddc task list --status running # Filter by status
ddc task get <task-id> # Show a single task
ddc task cancel <task-id> # Cancel a running taskSchedule jobs for an app (an HTTP request to the app, or an SSH command in the app directory) or a host (an SSH command). Crons need a paid plan.
ddc cron list --app <app-id> # Or --host <host-id>
ddc cron get <cron-id>
# HTTP cron: calls https://<app hostname>/api/cron every 15 minutes
ddc cron create --app <app-id> --type http --schedule "*/15 * * * *" --path /api/cron
# Command cron: runs in the app directory as the app user, with the app env
ddc cron create --app <app-id> --type command --schedule "0 3 * * *" --command "npm run cleanup"
# Host cron: runs as the host SSH user, with the host env
ddc cron create --host <host-id> --type command --schedule "0 * * * *" --command "df -h /"
ddc cron update <cron-id> --schedule "*/30 * * * *" --notify failed,success
ddc cron update <cron-id> --disabled
ddc cron run <cron-id> --wait # Run now and print the result (exit code 1 if it failed)
ddc cron runs <cron-id> # Recent runs: trigger, status, HTTP/exit code, duration
ddc cron delete <cron-id>The first HTTP cron on an app generates CRON_SECRET on the app env. Redeploy the app once so it receives the value, and check Authorization: Bearer $CRON_SECRET in your handler.
| Option | Description | Default |
|---|---|---|
--app |
App to run the cron for (create only) | - |
--host |
Host to run the cron on (create only) | - |
--type |
http (apps only) or command |
- |
--schedule |
5-field cron expression | - |
--timezone |
IANA timezone, alias --tz |
UTC |
--path |
HTTP path on the app | - |
--method |
GET or POST |
GET |
--authEnvVar |
App env var holding the bearer secret, alias --secret |
CRON_SECRET |
--command |
Shell command, alias --cmd |
- |
--retries |
Retries on failure, 0 to 3 | 1 |
--notify |
When to send a notification: failed, success (comma separated) |
failed |
--disabled |
Create or update the cron as disabled (--enabled true to enable) |
- |
Show journal logs. Filter by task, app, or host, and optionally follow for new entries.
ddc logs --task <task-id>
ddc logs --app <app-id>
ddc logs --host <host-id>
ddc logs --app <app-id> --follow # Stream new log entries| Option | Description | Default |
|---|---|---|
--task |
Filter logs by task ID | — |
--app |
Filter logs by app ID | — |
--host |
Filter logs by host ID | — |
--type |
Log types (comma separated: info,warn,error,health,log,ai) |
info,warn,error |
--limit |
Number of records | 50 |
--follow, -f |
Continuously poll for new logs | false |
| Option | Description |
|---|---|
--api-key <key> |
API key (overrides stored auth and env var) |
--base-url <url> |
API base URL (default: https://dollardeploy.com) |
--json |
Output as JSON (machine-readable) |
--verbose, -v |
Enable verbose logging |
--help, -h |
Show help |
--version, -V |
Show version |
All commands support --json for structured, machine-readable output:
ddc host list --json
ddc deploy --url https://github.com/org/repo --hostId <id> --jsonFor get/list commands (app, host, host service), --json returns the full object — every field the API returns, including env — not just the curated columns shown in the plain-text table. Use --all to get the same full object in plain-text (key: value) form.
JSON output goes to stdout, while progress/status messages go to stderr, making it easy to pipe results into other tools.
| Variable | Description | Default |
|---|---|---|
DOLLARDEPLOY_API_KEY |
Your API key | — |
DOLLARDEPLOY_BASE_URL |
API base URL | https://dollardeploy.com |
| Provider | Type | Region | Image |
|---|---|---|---|
| Hetzner | cax11 |
fsn1 |
ubuntu-24.04 |
| DigitalOcean | s-2vcpu-4gb |
fra1 |
ubuntu-24-04 |
| Verda Cloud | CPU.4V.16G |
FIN-01 |
ubuntu-24.04 |
name: Deploy my app
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: "22"
- name: Deploy
env:
DOLLARDEPLOY_API_KEY: ${{ secrets.DOLLARDEPLOY_API_KEY }}
run: |
npm install -g @dollardeploy/cli
ddc deploy --url ${{ github.server_url }}/${{ github.repository }}Use the CLI as a Node.js library:
const { createApiClient, waitForTask, checkUrl } = require("@dollardeploy/cli");
const api = createApiClient({
apiKey: process.env.DOLLARDEPLOY_API_KEY,
baseUrl: "https://dollardeploy.com"
});
// List all hosts
const hosts = await api.listHosts();
// Create and provision a host
const host = await api.createHost("my-server");
await api.saveProvision(host.id, {
provider: "hetzner",
providerType: "cax11",
providerRegion: "fsn1",
image: "ubuntu-24.04"
});
const task = await api.startProvision(host.id);
await waitForTask(api, task.id);
// Deploy an app
const app = await api.createApp({
repositoryUrl: "https://github.com/org/repo",
hostId: host.id,
name: "my-app"
});
const buildTask = await api.buildApp(app.id, { deploy: true });
await waitForTask(api, buildTask.id);
// Verify deployment
await checkUrl(`https://${app.hostname}`);| Method | Description |
|---|---|
createHost(name?) |
Create a new host |
getHost(id) |
Get host details |
listHosts(status?) |
List all hosts |
updateHost(id, data) |
Update host configuration |
deleteHost(id) |
Delete a host |
testConnection(hostId) |
Test SSH connection |
prepareHost(hostId) |
Prepare host for deployments |
| Method | Description |
|---|---|
getProvision(hostId) |
Get provision config |
saveProvision(hostId, data) |
Save provision config |
provisionHost(hostId) |
Start provisioning |
startProvision(hostId) |
Alias for provisionHost |
getProviderConfig(provider, filters?) |
List a provider's regions, instance types, and images |
deprovisionHost(hostId, deleteHost?) |
Deprovision (deletes the host record when deleteHost is true, the default) |
| Method | Description |
|---|---|
listServices(hostId) |
List installed services |
getService(hostId, serviceId) |
Get a single service |
createService(hostId, type) |
Install a service |
deleteService(hostId, serviceId) |
Remove a service |
| Method | Description |
|---|---|
createApp(config) |
Create a new app |
getApp(id) |
Get app details |
listApps() |
List all apps |
updateApp(id, data) |
Update app configuration |
suggestApp(app) |
Get AI configuration suggestions |
buildApp(id, options?) |
Build app (optionally deploy) |
deployApp(id) |
Deploy built app |
deleteApp(id) |
Delete an app |
removeApp(id, options?) |
Remove app from host |
| Method | Description |
|---|---|
listCrons(query?) |
List crons, e.g. "appId=..." |
getCron(id) |
Get a cron |
createCron(data) |
Create a cron |
updateCron(id, data) |
Update a cron |
deleteCron(id) |
Delete a cron |
runCron(id) |
Queue a run now, returns the task |
listCronRuns(cronId, limit?) |
Recent runs of a cron (default 10) |
| Method | Description |
|---|---|
listSshKeys() |
List all SSH keys |
createSshKey(data) |
Create an SSH key |
deleteSshKey(id) |
Delete an SSH key |
| Method | Description |
|---|---|
getTemplates() |
List all templates |
getTemplate(id) |
Get template details |
launchTemplate(config) |
Launch from template |
| Method | Description |
|---|---|
getTask(id) |
Get task status |
listTasks(status?) |
List tasks (optionally filter) |
cancelTask(id) |
Cancel a running task |
getTaskJournal(id) |
Get task logs |
getLogs(params) |
Query journal logs with filters |
| Method | Description |
|---|---|
getUser() |
Get current user info |
- Website: dollardeploy.com
- CLI Docs: docs.dollardeploy.com
- API Reference: dollardeploy.com/apidocs
- GitHub: github.com/dollardeploy
- Discord: Join our community
CLI is licensed under MIT © DollarDeploy