Guides
JSON and automation
Deploy from scripts and verify the result without parsing terminal output.
Use --json when a script or agent needs structured results. MCP returns the same result format.
Deploy and verify
From the project folder:
hub deploy --jsonThe result means the release was accepted, not that it is running. Read data.target and data.release.number, then check that release:
hub app my-app status --release 3 --jsonReplace the app and release number with the returned values. Poll every few seconds until running, failed, or superseded. Only running confirms a successful deployment.
Then get the URL and service state:
hub app my-app status --jsonRead serving and latest releases
In hub apps --json, each entry in data.apps has a release for the serving release, or null if none has run. hub app my-app status --json uses the same meaning for data.release. A distinct newer attempt appears as latestRelease; it is null when there is no newer attempt.
For example, if release 1 serves and release 2 fails, release.number is 1 and latestRelease.number is 2, with status failed. Check latestRelease for deployment failures without mistaking them for the serving release's state.
With status --release 3, data.release is the requested release 3. Use this exact-release lookup to verify a deployment, rollback, or environment change.
Wait for lifecycle operations
Start, stop, restart, and suspend wait for completion by default, including CLI JSON and MCP. To return before completion:
hub app my-app restart --no-wait --json
hub app my-app runtime --operation ID --jsonReplace ID with data.operation.id from the first response. Poll the same app and instance until data.operation.status leaves queued or running. Only succeeded confirms completion. Inspect failed, expired, or unknown results before retrying; an unknown result does not mean the action never happened.
For MCP, pass wait: false to hub_app_start, hub_app_stop, hub_app_restart, or hub_app_suspend:
{ "target": "my-app", "wait": false }Poll the returned operation ID with the read-only hub_app_runtime tool:
{ "target": "my-app", "operation": "123e4567-e89b-42d3-a456-426614174000" }Runtime policy changes use hub_app_runtime_set and still return an operation ID to poll. See runtime and sleep for policy settings and permissions.
Handle a failure
hub app my-app logs --build --release 3 --tail 100 --jsonUse the log to fix the cause. Check truncated before assuming you have the complete output.
Commands return ok and either data or an error with code, message, and an optional hint. Errors exit nonzero. Branch on error.code; do not parse human-readable output.
After a timeout, check release history before retrying: Hub may already have accepted the request. Verify releases returned by rollback and environment changes the same way.
Errors that need action
error.code | What to do |
|---|---|
needs_choice | The requested pushed source is unavailable, for example because the branch has never been pushed, the remote is not GitHub, or HEAD is detached. Push a branch to GitHub, or choose --local if uploading local files matches the intended source. Do not switch sources silently. |
github_auth_required | Open the returned installation link, approve GitHub access, then retry. The message distinguishes private-repository read access from push-to-deploy webhooks. Public repositories need no read grant; watching requires a webhook grant. |
cli_outdated | The platform requires a newer CLI. Follow error.hint to update, then retry. The CLI exits with code 3. Disabling update checks does not bypass the platform's minimum version. |
Deploy on every push
For continuous deployment, connect GitHub with watching enabled:
hub deploy --git owner/repository --watch --jsonWatching requires a GitHub webhook grant, even for public repositories. Once enabled, Hub deploys pushes without requiring a CLI login in each CI job. New or replacement repositories default to watching off; omitting --watch preserves the setting for the same repository. Use --no-watch to disable it explicitly.
For scripts on your own machine, run hub login once and protect its saved credentials.