CLI Command Reference

Every DeployYourApp CLI command and flag, with defaults, behavior, and example output.


Complete reference for the dya binary. Commands are grouped by area: auth, project, deploy, apps, channels, keys, and organizations.

Global options

Option Type Default Description
-h, --help flag Show help for the program or a command. Exits 0.
-V, --version flag Print the CLI version, read from the installed package's package.json. Exits 0.

Most commands operate on two pieces of context:

  • The active organization, stored in the global config. If your account belongs to exactly one organization, it is resolved and cached automatically the first time a command needs it — deploy, rollback, apps, channels, and keys all work without ever running dya orgs switch. With more than one organization and none selected, those commands fail and tell you to run dya orgs switch.
  • The project config, a .deployyourapp file in the current directory written by dya init or dya setup. See Configuration.

Every command exits non-zero on failure. Usage errors (an unknown command, a missing required flag) exit 1 via the argument parser; runtime failures exit 1 after printing the server's error message.

Auth commands

dya login

Authenticates the CLI. With no flags it runs the browser flow; with --api-key it stores a key for non-interactive use. Either way the credential is verified against the server before login is reported as successful, and a rejected credential is deleted rather than left on disk.

Option Type Default Description
--api-key <key> string Use an API key instead of browser auth. Validated with a request to /api/orgs.
--no-browser flag Print the authorization URL instead of opening a browser. For SSH sessions, containers, and machines with no desktop.
--server <url> string API server base URL, for a non-default environment such as a local development server. Trailing slashes are stripped and the value is persisted in the global config. Leave it unset to use DeployYourApp.

Storing one credential clears the other: an API key login deletes any stored session token, and a browser login deletes any stored API key.

dya login
ℹ Authenticate your account at:
  https://app.deployyour.app/auth/cli-auth?session=cms9dczwb00006cu4ryck0hdc

Press ENTER to open in the browser...
- Waiting for you to authorize the CLI...
✓ Logged in as ada@example.com

The URL is printed before anything opens, so you can copy it to another machine or browser profile rather than using the default one. --no-browser skips the ENTER prompt and the launch entirely.

If your account has two-factor authentication enabled, the browser flow enforces it — the CLI never handles your password or authenticator secret, only the session token the browser hands back.

# Non-interactive, for CI
dya login --api-key "$DEPLOY_YOUR_APP_API_KEY"

How the browser flow works

The CLI opens a pending login on the server, shows you where to approve it, and polls until you do. Nothing listens on your machine, so this works over SSH, inside containers, and when your browser runs on a different host entirely.

  1. POST /api/auth/cli-auth/session creates a pending request and returns a session id, a secret poll token, and the login URL.
  2. You approve in the browser. The page shows which client is asking, the IP it came from, and when — so a request you did not start is recognisable.
  3. The CLI polls GET /api/auth/cli-auth/session/:id, which answers 202 while pending and 200 with the token once approved.

The session id appears in the login URL; the poll token never does, and travels only in the X-Poll-Token header. Knowing a URL you pasted into chat is therefore not enough to steal the credential. Approval is single-use — a second claim gets 410, so a replayed poll cannot mint a second token.

A pending request expires after 10 minutes. Denying in the browser fails the waiting terminal immediately rather than leaving it to time out. A dropped network connection does not end the flow; the CLI keeps polling.

The returned token is a 30-day session, written to the global config with 0600 permissions.

CLI 0.1.x used a localhost callback server on ports 98769895. The server still accepts that flow so already-installed copies keep working.

dya logout

Deletes the stored session token and API key from the global config. Takes no options and makes no network request.

dya logout
✓ Logged out

dya whoami

Shows the current credential. With a session token it prints your name and email from /api/auth/get-session. With an API key it prints the key prefix plus the organizations the key's owner belongs to, because API keys have no session to report.

dya whoami
Logged in as:
  Name:  Ada Lovelace
  Email: ada@example.com
  Org:   org_2f8c1d94ab

With an API key:

ℹ Authenticated with API key (dya_1a2b...)
  Orgs:  acme
  Active org: org_2f8c1d94ab

Exits 1 when nothing is stored, when the session has expired, or when the key is no longer valid.

Project commands

dya setup

Interactive wizard for a Capacitor project: authenticate, pick or create the app, write the project config, generate keys, install the plugin, and write the plugin configuration. Requires a TTY — in CI it prints an error and exits 1.

Option Type Default Description
--server <url> string API server base URL, for a non-default environment such as a local development server. Persisted in the global config.
cd your-capacitor-app
dya setup

The steps, in order:

  1. Persists --server if given.
  2. Runs the browser login when neither a token nor an API key is stored. Declining exits 1.
  3. Resolves the organization, auto-selecting when there is exactly one, otherwise showing a numbered picker. An account with no organization exits 1.
  4. Detects package.json and @capacitor/core and asks for confirmation before continuing if either is missing.
  5. Offers the organization's existing apps plus a "Create a new app" entry. New apps are created with platform both and app IDs are re-prompted until they validate.
  6. Prompts for a default channel and writes .deployyourapp.
  7. Offers dya keys generate when dya-signing-private.pem is absent.
  8. Offers to install @deploy-your-app/capacitor-update-manager with pnpm, yarn, or npm, chosen from the lockfile present.
  9. Merges appId, channel, and the signing publicKey into plugins.DeployYourApp in capacitor.config.json. For .ts and .js configs it prints a snippet instead of rewriting code. updateUrl and statsUrl are added only when the CLI is pointed at a non-default server.
  10. Asks whether to embed the encryption private key in the Capacitor config, defaulting to no and warning that it must not land in a public repository.
  11. Offers to run npx cap sync.

dya init

Creates or updates the .deployyourapp project config in the current directory and auto-detects the built web assets directory. An existing config is updated in place, with a warning. The detected path is stored relative and forward-slashed so the file is portable across machines.

Option Type Default Description
--app-id <appId> string Existing value, else empty App ID, for example com.example.app. Must start with a letter and contain only letters, numbers, ., _, or -. An invalid value exits 1.
--channel <channel> string production Default channel written to the config.
dya init --app-id com.example.app
ℹ Detected web assets at: dist/spa
✓ Created .deployyourapp config
{
  "appId": "com.example.app",
  "channel": "production",
  "path": "dist/spa"
}

Omitting --app-id on a fresh project writes the config anyway and warns that deploys will not work until it is set.

Deploy and rollback

dya deploy

Bundles the web assets, optionally encrypts them, checksums and signs the result, uploads it, and points a channel at it.

Option Type Default Description
--channel <channel> string channel from .deployyourapp, else production Channel to deploy to.
--version <version> string Auto-generated Bundle version. Must match x.y.z where each part is digits.
--rollout <percent> integer 100 Percentage of devices eligible for the update. 0 is honored. Validated by the CLI: must be a whole number from 0 to 100. Anything else — abc, 50.5, 50%, 101, -1 — is rejected before any work happens, with error: option '--rollout <percent>' argument '…' is invalid. Rollout must be a whole number between 0 and 100. and exit 1.
--message <msg> string Release notes, stored on the bundle. Maximum 5000 characters.
--no-deploy flag Deploys Upload the bundle without pointing any channel at it.
--path <dir> string path from .deployyourapp, else auto-detected Directory of built web assets.
--target <platform> string capacitor capacitor or electron.
npm run build
dya deploy --channel production --message "Fix checkout validation"
ℹ Assets: /home/ada/shop/dist/spa
✔ App: Shop (com.example.shop)
ℹ Version: 2026.0731.142530
ℹ Channel: production
ℹ Platform: capacitor
✔ 42 files to bundle
✔ Archive: 3.4 MB
✔ Encrypted with AES-256
✔ Signed with RSA-4096
✔ Uploaded: 2026.0731.142530 (3.4 MB)
✔ Deployed to production at 100% rollout

✓ Deploy complete! Version 2026.0731.142530 is live.

More examples:

# Gradual rollout
dya deploy --channel production --rollout 25

# Upload without releasing; deploy it later from the dashboard
dya deploy --no-deploy --version 1.4.0

# Electron build
dya deploy --target electron --channel beta --path dist/electron

Pipeline order

The order matters, because the server and the device both verify the exact bytes that were uploaded:

  1. Walk the assets directory and hash every file. This is a local pre-flight check — it reports the file count, fails the deploy if the directory holds no files, and warns if there is no root index.html. The hashes are not uploaded; nothing in the platform implements delta updates from them.
  2. ZIP the directory, excluding any node_modules, .git, or .DS_Store path segment.
  3. Encrypt, if dya-encryption-public.pem exists in the current directory. AES-256-GCM with a random session key, which is then wrapped with RSA-OAEP-SHA256 using the encryption public key.
  4. Checksum the bytes produced by step 3 with SHA-256.
  5. Sign those same bytes with RSA-4096 (SHA-256), if dya-signing-private.pem exists in the current directory.
  6. Upload the bytes plus the metadata.
  7. Create a deployment on the target channel, unless --no-deploy was passed.

Because encryption runs before the checksum and signature, both cover the encrypted payload. There is no --encrypt flag: encryption is on whenever the encryption public key file is present. The legacy filenames .deployyourapp-encrypt.pem and .deployyourapp-private.pem are still accepted as fallbacks.

Deploy behavior and failure modes

  • Version format. Auto-generated versions use YYYY.MMDD.HHMMSS with second granularity, so back-to-back CI deploys do not collide. Versions are unique per app, across platforms — the same version cannot be uploaded twice for one app even with different --target values.
  • Asset detection. When neither --path nor a configured path is given, the CLI tries dist/spa, dist/pwa, dist, www, build, public in that order and accepts only a directory containing an index.html. Finding nothing exits 1.
  • Empty or wrong assets directory. --path is taken at face value — it skips the index.html check that auto-detection applies. If the directory contains no files at all the deploy stops before uploading anything and exits 1; if it has files but no root index.html, the CLI warns and continues.
  • Unsigned bundles. With no signing key the CLI warns and omits the signature. The server accepts that only for apps with no registered public key; otherwise the upload is rejected.
  • Missing channel. The upload happens before the channel is looked up. If the channel does not exist, the bundle is already on the server but the deploy step fails and exits 1. Create the channel with dya channels create --name <name>, then release the uploaded bundle from the dashboard — re-running dya deploy with the same version is rejected as a duplicate.
  • Two-factor uploads. If the organization requires a two-factor code for uploads, the CLI prompts for a 6-digit code and retries the upload. This needs a TTY, so it cannot be satisfied in a pipeline.
  • Server limits. Bundles are capped at 500 MB, and uploads are rate limited to 30 per hour.

dya rollback

Points a channel back at a previous bundle. Without --bundle the server picks the deployment before the current one; with no previous deployment the command fails. Rollbacks always deploy at 100% rollout.

Option Type Default Description
--channel <channel> string channel from .deployyourapp, else production Channel to roll back. Resolved exactly the way dya deploy resolves it.
--bundle <bundleId> string Previous bundle Roll back to this specific bundle ID instead.

dya rollback and dya deploy pick the channel the same way — flag, then the project config, then production — so a bare dya rollback always undoes what a bare dya deploy shipped. The channel is printed before any network request, so you can see what is about to be rolled back:

# In a project whose .deployyourapp says "channel": "beta"
dya rollback
ℹ Channel: beta
✔ App: Shop
✔ Rolled back beta
✓ Rollback complete

Pass the flag to override the project config:

dya rollback --channel production
ℹ Channel: production
✔ App: Shop
✔ Rolled back production
✓ Rollback complete

App commands

dya apps list

Lists the apps in the active organization. Takes no options.

dya apps list
Apps (1):

  Shop (com.example.shop)
    Platform: both  Channels: 2  Bundles: 12  Devices: 340

dya apps create

Creates an app in the active organization. A production channel is created with it and marked as the default.

Option Type Default Description
--name <name> string required Display name, 1–100 characters.
--app-id <appId> string required Bundle/app identifier. Must start with a letter and contain only letters, numbers, ., _, or -.
--platform <platform> string both One of ios, android, both (Capacitor), or electron. An app targets one bundle family — create a separate app to ship desktop.
dya apps create --name "Shop" --app-id com.example.shop --platform both
✔ Created app: Shop

App IDs are globally unique across the whole platform, not just your organization. Reusing one that is already registered fails with a conflict.

Channel commands

Channel commands resolve the app from the appId in .deployyourapp, so run them from the project directory.

dya channels list

Lists the channels for the current app with the bundle each one currently serves. Takes no options.

dya channels list
Channels for Shop:

  production [default]  →  2026.0731.142530
  beta  →  no bundle

dya channels create

Option Type Default Description
--name <name> string required Channel name, 1–50 characters, starting with a letter and containing only letters, numbers, -, or _.
dya channels create --name beta
✔ Created channel: beta

dya channels delete

Deletes a channel by name. The default channel cannot be deleted; the server rejects that with a permission error.

Option Type Default Description
--name <name> string required Channel to delete.
dya channels delete --name beta
✔ Deleted channel: beta

Key commands

RSA private keys are generated locally and never leave your machine. Only the two public keys are sent to the server, and the encryption private key is meant for your app binary, not for upload.

dya keys generate

Generates two RSA-4096 key pairs in the current working directory, then uploads the public halves to the server when an organization and app can be resolved.

Option Type Default Description
--app-id <appId> string appId from .deployyourapp App to upload the public keys to.
File Written with Purpose
dya-signing-private.pem mode 0600 Signs bundles during dya deploy. Never leaves your machine, never commit it.
dya-signing-public.pem default mode Uploaded to the server for signature verification.
dya-encryption-public.pem default mode Encrypts bundles during dya deploy. Also uploaded to the server.
dya-encryption-private.pem mode 0600 Decrypts bundles on device. Embed it in your app binary. Never upload it.
dya keys generate
✔ Generated RSA-4096 key pairs

ℹ Signing keys generated:
ℹ   Private key: /home/ada/shop/dya-signing-private.pem (keep secret, use to sign bundles)
ℹ   Public key:  /home/ada/shop/dya-signing-public.pem (uploaded to the server)

ℹ Encryption keys generated:
ℹ   Public key:  /home/ada/shop/dya-encryption-public.pem (keep with CLI, used to encrypt bundles)
ℹ   Private key: /home/ada/shop/dya-encryption-private.pem (EMBED IN YOUR APP — this is the decryption key)

⚠ Keep dya-signing-private.pem safe! Never commit it to version control.
✔ Signing + encryption public keys uploaded to server

For Capacitor, set the encryption private key at plugins.DeployYourApp.encryptionPrivateKey in your Capacitor config. For Electron, pass it to the ElectronUpdateManager constructor as config.encryptionPrivateKey.

If dya-signing-private.pem already exists the command prints the existing paths, points you at dya keys upload, and exits 0 without overwriting anything. Delete the files to regenerate. If the upload fails — for example you are not logged in yet — the keys are still written and the command tells you to run dya keys upload later.

dya keys upload

Reads dya-signing-public.pem and, when present, dya-encryption-public.pem from the current directory and uploads them. Use this when the keys were generated on another machine, or when the upload during dya keys generate was skipped.

Option Type Default Description
--app-id <appId> string appId from .deployyourapp App to upload the public keys to.
dya keys upload --app-id com.example.shop
✔ Signing + encryption public keys uploaded
✓ Keys uploaded

Exits 1 if there is no signing public key in the directory, or if no organization and app ID can be resolved.

Organization commands

dya orgs list

Lists the organizations you belong to and marks the active one. Takes no options.

dya orgs list
Organizations (2):

  Acme Inc (acme) ← active
    Role: owner  Members: 4  Apps: 3  Plan: Scale
  Side Project (side-project)
    Role: owner  Members: 1  Apps: 1  Plan: Launch

dya orgs switch

Sets the active organization in the global config.

Option Type Default Description
--slug <slug> string Organization slug, or its exact name. An unknown value exits 1.
dya orgs switch --slug acme
✓ Switched to: Acme Inc (acme)

Without --slug: a single-organization account is selected silently; a multi-organization account gets a numbered picker on a TTY, and in a non-interactive shell the command prints the --slug hint and exits 1.

Single-organization accounts rarely need this command, because the other commands auto-select the only organization and cache it.


Previous
Installation
Next
Configuration