This CLI is built for humans at a terminal (interactive prompts, OAuth browser login, colorized output) but every interactive surface has a non-interactive path so it can be driven by an AI agent, a CI job, or any other automated caller. This document is the reference for that non-interactive usage.
The two flags you almost always want are --non-interactive (never prompt) and
--json (machine-readable output). Combine them with a token in the environment
and the CLI runs end-to-end with no TTY and no browser.
Set a token in the environment instead of running the OAuth login flow:
export DENO_DEPLOY_TOKEN=ddp_xxxxxxxxxxxxxxxx # generate at <endpoint>/account/tokens-
When
DENO_DEPLOY_TOKEN(or--token <token>) is set, the CLI uses it directly and never opens a browser or prompts for login. -
An invalid or expired token fails with exit code
3(AUTH) and a message telling you to regenerate the token and re-exportDENO_DEPLOY_TOKEN— it does not fall back to the browser flow. -
Verify auth without side effects:
deno deploy whoami --json # {"authenticated":true,"user":{...},"tokenType":"...","orgs":[...]}
Pass --non-interactive (alias -y) to make the CLI refuse to prompt. It is
also implied automatically when stdin is not a TTY. In this mode any value that
would have been asked for interactively must be supplied via a flag or env var;
a missing value fails fast with exit code 2 (USAGE) and an error naming the
exact flag to pass, e.g. Use --org to specify the organization.
Values that can come from the environment:
| Env var | Equivalent flag | Used for |
|---|---|---|
DENO_DEPLOY_TOKEN |
--token |
auth token |
DENO_DEPLOY_ORG |
--org |
default organization slug |
DENO_DEPLOY_APP |
--app |
default application slug |
DENO_DEPLOY_ENDPOINT |
--endpoint |
API endpoint (defaults to prod) |
Pass --json (alias -j) to any command. It emits a single JSON object or
array on stdout and nothing else — no spinners, no progress bars, no ANSI
color. Human progress still goes to stderr, so
deno deploy publish --json | jq is safe to pipe.
Errors in --json mode are emitted as a single object on stderr:
{
"error": { "code": "AUTH", "message": "...", "hint": "...", "traceId": "..." }
}code is a stable error identifier when one is known (e.g.
AUTH_INVALID_TOKEN, NON_INTERACTIVE_REQUIRED, VALIDATION_ERROR,
SLUG_ALREADY_IN_USE), falling back to the symbolic name of the exit code (see
below); hint and traceId may be absent. Invalid or unknown flags also
produce this envelope (with exit code 2), so a bad invocation never emits
free-form text on a --json run.
| Code | Name | Meaning |
|---|---|---|
| 0 | OK | success |
| 1 | GENERIC | unclassified error |
| 2 | USAGE | missing/invalid flag or argument |
| 3 | AUTH | missing, invalid, or expired token |
| 4 | NOT_FOUND | org / app / database / resource does not exist |
| 5 | CONFLICT | resource already exists (re-running create, etc.) |
| 6 | NETWORK | backend or network failure |
Stack traces are printed only when --debug is set; otherwise errors are a
single line (or the JSON envelope above).
These work on every subcommand:
| Flag | Description |
|---|---|
-j, --json |
Emit JSON on stdout instead of human-readable output |
-y, --non-interactive |
Fail fast instead of prompting |
-q, --quiet |
Suppress non-essential output |
--token <token> |
Auth token (overrides DENO_DEPLOY_TOKEN) |
--config <path> |
Path to the config file |
--ignore <path> |
Ignore particular source files (repeatable) |
--debug |
Enable debug output and stack traces |
--endpoint <url> |
API endpoint (hidden from --help; no trailing /) |
Only the agent-relevant flags are listed; run deno deploy <cmd> --help for the
full set.
deno deploy [root-path] — build and deploy the app in root-path.
--org <name>,--app <name>— target org/app--prod— deploy directly to production--no-wait— return as soon as the build is queued, don't stream it--allow-node-modules— includenode_moduleswhen uploading
deno deploy create [root-path] — create a new application. Supply every flag
to run non-interactively.
--org <name>,--app <name>--dry-run— validate/process flags without creating the app--no-wait--source <github|local>and, for github:--owner <name>,--repo <name>--runtime-mode <dynamic|static>- dynamic:
--entrypoint <file>,--arguments <arg>(repeatable),--working-directory <dir> - static:
--static-dir <dir>,--single-page-app
- dynamic:
--framework-preset <preset>,--install-command,--build-command,--pre-deploy-command,--app-directory <path>--region <region>,--build-timeout <minutes>,--build-memory-limit <megabytes>
All mutations emit a single JSON result object on stdout under --json.
env list— list env varsenv add <variable> <value> [--secret]env update-value <variable> <value>env update-contexts <variable> [new-contexts...]env delete <variable>env load <file> [--non-secrets] [--replace | --skip-existing]—--replace/--skip-existingdecide what happens to already-defined keys without prompting (required knowledge for non-interactive runs); the--jsonresult reportsadded/updated/skippedkeys
All mutations emit a single JSON result object on stdout under --json.
database provision <name> --kind <denokv|prisma> [--region <region>]database link <name> <connectionString>ordatabase link <name> --hostname <host> [--username --password --port --cert](the two forms are mutually exclusive; add--dry-runto test only)database assign <name> [--app <name>]database detach <name> [--app <name>]database list [search]— for Deno KV databases the--jsonoutput includesdatabaseIdand aconnectUrlusable withDeno.openKv()database query <name> <database> [query...]database delete <name>
logs --once— drain the currently available (backfilled) logs, then exit 0 instead of tailing live; defaults to the last hour, widen with--start <iso-date>(and optionally bound with--end). With--json, output is NDJSON: one log record per line on stdout.
sandbox createin non-interactive mode requires an explicit--timeout <duration>(e.g.--timeout 15m): the defaultsessiontimeout destroys the sandbox when the command exits. The--jsonresult is{id, org, timeout}; clean up withsandbox kill <id>.
apps list [--org <name>] [--limit <n>] [--cursor <c>]apps get [--org <name>] [--app <name>]— includesproductionUrl,domains, and revision timelinesorgs listdeployments list [--org <name>] [--app <name>] [--limit <n>] [--cursor <c>]whoami
--cursor takes the pagination cursor returned by a previous --json run.
All examples assume DENO_DEPLOY_TOKEN is exported.
1. Check auth and resolve the current identity
deno deploy whoami --json | jq -r '.user.githubLogin'2. Create a static site and deploy it
deno deploy create ./site \
--non-interactive --json \
--org my-org --app my-site \
--source local --runtime-mode static --static-dir dist --region us3. Deploy an existing app to production and capture the URL
url=$(deno deploy --non-interactive --json --org my-org --app my-site --prod \
| jq -r '.productionUrl')
echo "deployed to $url"(.url is the console build page for the revision; .productionUrl is the
served application URL. With --no-wait the build is still pending, so only
revisionId and url are available.)
4. Set environment variables
deno deploy env add API_KEY "$API_KEY" --secret --non-interactive --org my-org --app my-site
deno deploy env list --json --org my-org --app my-site5. List the most recent deployments as JSON
deno deploy deployments list --json --org my-org --app my-site --limit 5There are no no-op guarantees. When the backend reports a conflict (HTTP 409),
the CLI exits 5 (CONFLICT) with an error code such as SLUG_ALREADY_IN_USE.
Do not blindly treat exit 5 as "already done": the conflicting resource may
belong to someone else or differ from what you tried to create — inspect the
current state (apps list, env list, database list) before deciding.
Partial state is possible: create registers the app before deploying, so a
failed build leaves the app existing and a re-run will conflict; recover with
deno deploy --app <name> instead of create.