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, andkeysall work without ever runningdya orgs switch. With more than one organization and none selected, those commands fail and tell you to rundya orgs switch. - The project config, a
.deployyourappfile in the current directory written bydya initordya 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.
POST /api/auth/cli-auth/sessioncreates a pending request and returns a session id, a secret poll token, and the login URL.- 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.
- The CLI polls
GET /api/auth/cli-auth/session/:id, which answers202while pending and200with 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 9876–9895. 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:
- Persists
--serverif given. - Runs the browser login when neither a token nor an API key is stored. Declining exits
1. - Resolves the organization, auto-selecting when there is exactly one, otherwise showing a numbered picker. An account with no organization exits
1. - Detects
package.jsonand@capacitor/coreand asks for confirmation before continuing if either is missing. - Offers the organization's existing apps plus a "Create a new app" entry. New apps are created with platform
bothand app IDs are re-prompted until they validate. - Prompts for a default channel and writes
.deployyourapp. - Offers
dya keys generatewhendya-signing-private.pemis absent. - Offers to install
@deploy-your-app/capacitor-update-managerwith pnpm, yarn, or npm, chosen from the lockfile present. - Merges
appId,channel, and the signingpublicKeyintoplugins.DeployYourAppincapacitor.config.json. For.tsand.jsconfigs it prints a snippet instead of rewriting code.updateUrlandstatsUrlare added only when the CLI is pointed at a non-default server. - 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.
- 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:
- 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. - ZIP the directory, excluding any
node_modules,.git, or.DS_Storepath segment. - Encrypt, if
dya-encryption-public.pemexists 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. - Checksum the bytes produced by step 3 with SHA-256.
- Sign those same bytes with RSA-4096 (SHA-256), if
dya-signing-private.pemexists in the current directory. - Upload the bytes plus the metadata.
- Create a deployment on the target channel, unless
--no-deploywas 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.HHMMSSwith 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--targetvalues. - Asset detection. When neither
--pathnor a configuredpathis given, the CLI triesdist/spa,dist/pwa,dist,www,build,publicin that order and accepts only a directory containing anindex.html. Finding nothing exits1. - Empty or wrong assets directory.
--pathis taken at face value — it skips theindex.htmlcheck that auto-detection applies. If the directory contains no files at all the deploy stops before uploading anything and exits1; if it has files but no rootindex.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 withdya channels create --name <name>, then release the uploaded bundle from the dashboard — re-runningdya deploywith 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.