CLI Reference
CLI Commands
Authentication
zevcloud login
Add a team to the CLI by pasting its API key. ZevCloud API keys are team-scoped (one key = one team), so a user who’s a member or admin of multiple teams configures each one separately and switches between them with team switch.
zevcloud login If you’re already logged in to one team, login adds the new team alongside it and makes the new one active. Run it again per team you belong to.
zevcloud logout
Remove the active team from the CLI. Other configured teams remain.
# Log out of just the active team
zevcloud logout
# Wipe every configured team
zevcloud logout --all zevcloud whoami
Show the active team, its API URL, and a list of any other teams you’ve configured.
Teams
zevcloud team list
List every team you’ve configured. The active team is marked with a check.
zevcloud team list zevcloud team switch [nameOrId]
Switch the active team. Pass a name, slug, or id to switch directly, or run with no argument for an interactive picker.
# Interactive picker
zevcloud team switch
# Direct switch by name
zevcloud team switch acme-corp zevcloud team remove <nameOrId>
Remove a configured team’s stored API key. If you remove the active team, the CLI auto-selects another configured team as active.
--team <nameOrId> flag (any command)
Override the active team for a single invocation without changing your default. Useful in scripts and one-off cross-team commands.
# Deploy in the "side-project" team without switching out of "main"
zevcloud --team side-project deploy a1b2c3d4-...
# List services in another team
zevcloud --team acme-corp services Projects
zevcloud projects
List all projects in the active team.
zevcloud projects Services
zevcloud services [projectId]
List services. Optionally filter by project.
# All services across all projects
zevcloud services
# Services in a specific project
zevcloud services 6412b9be-13ef-469c-b451-311439a8a9cd Creating a service
zevcloud init
Interactive wizard that creates a new service from the current directory and triggers its first deploy. Walks you through project, source, framework, and plan picks, then handles the build end-to-end.
# Run from inside your project directory
cd my-app
zevcloud init What init does, in order:
- Detect the source mode. Looks at the current directory:
- GitHub remote found (a
.git/with a GitHub origin URL): defaults to GitHub-source. The CLI confirms the repo + branch with you and probes whether the repo is public or private. Public repos clone directly. Private repos require the ZevCloud GitHub App to be installed with access to the repo — if it isn’t, the CLI prints an install URL and waits for you to grant access in your browser, then continues. - No git, or remote isn’t GitHub: defaults to direct terminal upload. The CLI tars your current directory (respecting
.gitignoreand.zevcloudignore) and uploads it via a pre-signed URL. No GitHub setup required — useful for vibe-coder projects that haven’t been pushed anywhere yet.
- GitHub remote found (a
- Pick a project + environment. Lists existing projects or offers to create a new one inline. New projects get a default
Productionenvironment automatically. - Existing services in the chosen environment are listed first, so you can redeploy or run other actions (logs, restart, env, stop) against them instead of creating a new one. Picking
+ Create new servicecontinues with the wizard. - Service name + slug. The slug becomes part of your auto-generated URL (
<slug>.zevcloud.app). The CLI checks the slug is available before continuing. - Framework detection. Reads
package.jsonand common config files to pre-select the right framework — detected ones show(Detected — recommended)at the top of the picker so you can hit Enter. - Plan picker. Fetches the live plan catalog and renders a comparison. Picking a paid plan triggers a credit pre-flight — if you have plan credits available, the CLI confirms coverage. If not, the service is created anyway and an invoice URL is printed for you to settle in the dashboard. Free plan skips this step.
- Confirm summary of everything that’s about to happen. Cancel here if anything looks wrong.
- Create + upload + deploy. Creates the service, runs the source upload (for upload-mode), triggers the first build, and polls until it succeeds or fails. Prints the live URL at the end.
Upload mode requirements
In upload mode the framework picker in init offers Next.js, Astro, Nuxt, Remix, SvelteKit, Vite, and Node.js, so you can’t pick something that would fail at build time.
Uploads of Python, FastAPI, Django, Flask, Go, PHP and Ruby projects are supported through the API (see Uploading a backend), but the init picker doesn’t list them yet. To deploy one of those stacks from the CLI, use a GitHub repo for the source and the build detects the language automatically.
Source-tarball limits
Upload mode has a 200MB hard cap on the source tarball (plan-independent). If your project is bigger than that, almost always one of two things is happening:
node_modulesisn’t in your.gitignore. Add it.- You’re shipping large binary assets that belong on a CDN.
The cap stops accidental abuse but isn’t tied to your plan; production app sizes are typically a few MB.
Controlling what’s uploaded with .zevcloudignore
When you deploy in upload mode, the CLI tars your current directory and uploads it. The exclude list is built from three sources, applied in order:
- Built-in hard excludes — always skipped:
node_modules,.git, framework caches (.next,.nuxt,.svelte-kit,.astro,.turbo,.cache,.parcel-cache), build output (dist,build), local env files (.env.local,.env.development*,.env.test*),.DS_Store,.vscode,.idea, and*.logpatterns. .gitignore— every pattern in your repo’s.gitignoreis honored. Most projects need nothing else..zevcloudignore— optional. Same syntax as.gitignore, but only the CLI reads it. Use it when something belongs in your repo but should not be in your deploy (test fixtures, design source files, internal docs).
# .zevcloudignore example
# Test data we don't want shipped to the runtime container
test-fixtures/
*.test.snap
# Design source files (large .psd / .fig exports)
design/
# Internal-only docs
RUNBOOK.md Pattern syntax (subset of gitignore):
| Pattern | Meaning |
|---|---|
foo | Match foo anywhere in the tree (file or directory) |
foo/ | Same as above — the CLI treats both forms identically |
/foo | Leading slash is stripped; behaves the same as foo |
*.log | Glob: any path segment matching the pattern (single * only, no **) |
# comment | Lines starting with # are ignored |
Patterns are deliberately conservative — there’s no !negation, no ** recursion, and no per-directory .gitignore. If you need fine-grained inclusion, point the source at a Git repo instead.
Build-time vs runtime environment variables
ZevCloud injects two distinct kinds of env vars into your service. Knowing which is which avoids “I set DATABASE_URL and the build failed because it can’t find it” confusion:
| Where it’s available | What it’s for | How to set it |
|---|---|---|
| Build-time only | Compile/bundler inputs read by the build script. Next.js NEXT_PUBLIC_* baked into the static bundle, Vite VITE_* vars, Astro public vars, build-step API keys for prerendering. | Set via zevcloud env set before the next deploy. Anything you set is available in both stages by default. |
| Runtime only | Server-side config the app reads after boot: DATABASE_URL, third-party API secrets, feature flags. Not embedded in the bundle, so changing them is a restart, not a deploy. | Same — zevcloud env set, then zevcloud restart. No rebuild needed. |
The rule of thumb: if your framework’s docs say a variable must be set at build time (e.g. Next.js NEXT_PUBLIC_*), set it first and then run zevcloud deploy. If it’s pure runtime config, zevcloud env set + zevcloud restart is enough — the existing image is reused.
For secrets, pass -s / --secret:
# Secret runtime value (masked in dashboard, never echoed)
zevcloud env set <serviceId> DATABASE_URL postgres://... -s
# Public-bundle build-time value (Next.js example)
zevcloud env set <serviceId> NEXT_PUBLIC_API_URL https://api.example.com
zevcloud deploy <serviceId> # rebuild so the value is baked in Framework-specific notes
Most projects need nothing beyond the framework’s default config. A few stacks have quirks the build picks up automatically — knowing them helps when the runtime isn’t behaving as expected:
- Next.js — no
output: 'standalone'requirement. The runner copies the full.nextdirectory and runsnpm start, so any Next.js config works. Pages Router and App Router are both supported.NEXT_PUBLIC_*vars must be set before the deploy (build-time). - Astro — needs the Node SSR adapter (
@astrojs/node) if you have server routes or middleware. The build’s start command isnode ./dist/server/entry.mjs. Pure-static Astro projects work too, but consider deploying as a Static Site service for better performance. - Nuxt 3 — runs
node .output/server/index.mjs. Universal/SSR mode is the default; if you setssr: falseinnuxt.config.ts(SPA mode), the build still works but you may want a Static Site service instead. - SvelteKit — needs
@sveltejs/adapter-node. The runner executesnode build. The default adapter isadapter-auto, which usually resolves correctly, but pinningadapter-noderemoves ambiguity. - Remix —
npm startruns whatever yourpackage.jsondefines asstart. The default Remix template usesremix-serve build/index.js, which is fine; custom servers (Express, Hono) work too as long as they bind to0.0.0.0on the platform-providedPORT. - Vite — built artifacts are served via
vite preview --host 0.0.0.0 --port 4173. Suitable for SPA testing but not production-grade. For real production SPAs, deploy as a Static Site service instead and skip the Node runtime. - Node.js — generic catch-all. Runs
npm start. Yourpackage.jsonmust define astartscript that binds to0.0.0.0on$PORT. Pure-JS APIs, Express servers, custom workers — all fine.
The PORT contract: every web/worker service receives the listen port via the PORT env var. Hardcoding 3000 works for local dev but breaks in production. Always read process.env.PORT.
Lockfile is required. Upload mode looks at pnpm-lock.yaml, yarn.lock, or package-lock.json to pick the install command. If none exists, the build falls back to npm install (not npm ci) — slower and non-deterministic. Commit a lockfile.
Deployments and lifecycle
ZevCloud has four service types and the CLI commands behave differently per type — the tool figures out the right action automatically based on what you ran it against.
zevcloud deploy <serviceId>
Trigger a deployment of an existing service. The CLI knows the service’s source mode (GitHub or direct upload) and does the right thing automatically — pulls from your configured GitHub branch, or re-tars and re-uploads your current directory for upload-mode services.
When deploying to a service that’s currently running, the CLI shows a confirmation prompt with what’s about to be replaced so a stray Enter doesn’t take down production. The prompt is automatically skipped when stdin isn’t a TTY (CI, agents, scripts) — automation runs without hanging.
The exact action depends on the service type:
| Service type | What deploy does |
|---|---|
| Web app / worker (GitHub source) | Triggers a fresh build pulling from the configured branch; CLI polls and reports status |
| Web app / worker (upload source) | Re-tars CWD, uploads via the pre-signed flow, triggers the build, polls and reports status |
| WordPress (not yet provisioned) | Provisions WordPress, MariaDB, and SFTP for the service |
| WordPress (already running) | Refuses with guidance — the site is already live; use restart to recycle, or push files via SFTP / wp-admin |
| Static site | Refuses with guidance — static sites are updated by uploading files (dashboard or SFTP), then restart |
| Database | Refuses — databases don’t deploy; use restart, stop, or the dashboard |
zevcloud deploy a1b2c3d4-... For Git-based apps the command will:
- Trigger the build
- Poll status every 5 seconds
- Report when live (or if it failed)
zevcloud redeploy <serviceId>
Alias for deploy.
zevcloud restart <serviceId>
Recycle the service container. Works for any service type. Useful after env-var changes, file pushes via SFTP, or to clear a wedged container.
zevcloud restart a1b2c3d4-... Brief downtime per service (5–15 seconds depending on type).
zevcloud stop <serviceId>
Stop a service. Storage and config are preserved. restart brings it back up.
zevcloud stop a1b2c3d4-... Logs
zevcloud logs <serviceId> [options]
View runtime logs from a service container.
# Last 100 lines
zevcloud logs a1b2c3d4-...
# Last 500 lines
zevcloud logs a1b2c3d4-... -n 500
# Follow (tail) logs
zevcloud logs a1b2c3d4-... -f Options:
| Flag | Description |
|---|---|
-n, --lines <number> | Number of lines to show (default: 100) |
-f, --follow | Follow log output (polls every 5s) |
Environment Variables
Environment variables are most useful on web-app and worker services. They can be set on other types but won’t change runtime behavior — WordPress reads its config from the database, databases use baked-in credentials, and static sites have no runtime env.
zevcloud env list <serviceId>
List all environment variables for a service.
zevcloud env list a1b2c3d4-... Secret variables show •••••••• instead of their value.
zevcloud env set <serviceId> <key> <value> [options]
Set an environment variable.
# Regular variable
zevcloud env set a1b2c3d4-... DATABASE_URL postgres://...
# Secret variable
zevcloud env set a1b2c3d4-... API_SECRET sk_live_... -s Options:
| Flag | Description |
|---|---|
-s, --secret | Mark as secret (hidden in dashboard) |
zevcloud env remove <serviceId> <envVarId>
Remove an environment variable by its ID.
Configuration
zevcloud config [options]
Configure CLI settings.
# Set custom API URL
zevcloud config --api-url https://api.zevcloud.net/v1 Options:
| Flag | Description |
|---|---|
--api-url <url> | Set the API endpoint. HTTPS required — plaintext HTTP URLs are rejected to keep API keys off the wire in cleartext. |
Diagnostics
zevcloud version
Show the installed CLI version, the latest version on npm (when known), the time of the last update check, and your Node and platform info. Paste this into bug reports.
zevcloud version zevcloud --version (or -v) is also available and prints just the semver string for scripts.
zevcloud help [command]
Show the top-level command list, or detailed help for a specific command. zevcloud --help and zevcloud <command> --help work the same way.
# Top-level help
zevcloud help
# Help for a specific command
zevcloud help deploy
zevcloud deploy --help Environment Variables
The CLI honors a few environment variables, useful in CI pipelines and AI agent workflows:
| Variable | Purpose |
|---|---|
ZEVCLOUD_API_KEY | Authenticate without storing a key on disk. Takes precedence over the configured active team when set. |
ZEVCLOUD_TEAM_ID | Pair with ZEVCLOUD_API_KEY to set the team-id header explicitly. |
ZEVCLOUD_DISABLE_UPDATE_CHECK | Set to true to skip the daily “is there a newer version?” check. |
ZEVCLOUD_DISABLE_POSTINSTALL | Set to true to silence the postinstall welcome message. |
CI | Auto-detected. The CLI suppresses the postinstall message and the update-check banner when set. |
For a CI runner or AI agent, the recommended pattern is:
export ZEVCLOUD_API_KEY=sk_live_...
export ZEVCLOUD_TEAM_ID=<your-team-id>
zevcloud deploy <serviceId> When both variables are set the CLI never reads or writes the on-disk credential store, which keeps shared runners free of leftover credentials.
API Key Scopes
When generating an API key, you choose a scope. The CLI is bound to that scope on every request — it cannot escalate.
| Scope | Permissions |
|---|---|
| Read | List and inspect projects, services, deployments, env-var keys, logs, DNS, billing. No mutations. |
| Deploy | Everything Read can do, plus trigger deployments, restart/stop services, set or delete env vars, verify a custom domain. The right choice for CI and AI agents. |
| Full | Equivalent to a human admin. Adds project/service/environment create + delete, custom-domain management, terminal commands, SFTP password rotation, public DB toggling, and DNS-record management on purchased domains. |
Some actions — managing API keys themselves, deleting the team, inviting members, billing changes, buying domains, opening the database GUI, connecting GitHub — always require interactive authentication and cannot be done from the CLI even with a Full key. See api/auth for the full list.
Exit Codes
| Code | Meaning |
|---|---|
0 | Success |
1 | Error (authentication, deployment failure, etc.) |
Updated at, Monday, October 26, 2026