CLI Commands
Authentication
Section titled “Authentication”zevcloud login
Section titled “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.
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
Section titled “zevcloud logout”Remove the active team from the CLI. Other configured teams remain.
zevcloud whoami
Section titled “zevcloud whoami”Show the active team, its API URL, and a list of any other teams you’ve configured.
zevcloud team list
Section titled “zevcloud team list”List every team you’ve configured. The active team is marked with a check.
zevcloud team switch [nameOrId]
Section titled “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.
zevcloud team remove <nameOrId>
Section titled “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)
Section titled “--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.
Projects
Section titled “Projects”zevcloud projects
Section titled “zevcloud projects”List all projects in the active team.
Services
Section titled “Services”zevcloud services [projectId]
Section titled “zevcloud services [projectId]”List services. Optionally filter by project.
Creating a service
Section titled “Creating a service”zevcloud init
Section titled “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.
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
Section titled “Upload mode requirements”Upload mode supports any framework with an optimised Dockerfile template — currently Next.js, Astro, Nuxt, Remix, SvelteKit, Vite, and Node.js. The framework picker in init automatically filters to the supported set when you’re in upload mode, so you can’t pick something that would fail at build time.
If your stack isn’t in the list (Python, Go, Ruby, …), use a GitHub repo for the source and the build runs through nixpacks instead.
Source-tarball limits
Section titled “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
Section titled “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).
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
Section titled “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:
Framework-specific notes
Section titled “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
Section titled “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>
Section titled “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 |
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>
Section titled “zevcloud redeploy <serviceId>”Alias for deploy.
zevcloud restart <serviceId>
Section titled “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.
Brief downtime per service (5–15 seconds depending on type).
zevcloud stop <serviceId>
Section titled “zevcloud stop <serviceId>”Stop a service. Storage and config are preserved. restart brings it back up.
zevcloud logs <serviceId> [options]
Section titled “zevcloud logs <serviceId> [options]”View runtime logs from a service container.
Options:
| Flag | Description |
|---|---|
-n, --lines <number> | Number of lines to show (default: 100) |
-f, --follow | Follow log output (polls every 5s) |
Environment Variables
Section titled “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>
Section titled “zevcloud env list <serviceId>”List all environment variables for a service.
Secret variables show •••••••• instead of their value.
zevcloud env set <serviceId> <key> <value> [options]
Section titled “zevcloud env set <serviceId> <key> <value> [options]”Set an environment variable.
Options:
| Flag | Description |
|---|---|
-s, --secret | Mark as secret (hidden in dashboard) |
zevcloud env remove <serviceId> <envVarId>
Section titled “zevcloud env remove <serviceId> <envVarId>”Remove an environment variable by its ID.
Configuration
Section titled “Configuration”zevcloud config [options]
Section titled “zevcloud config [options]”Configure CLI settings.
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
Section titled “Diagnostics”zevcloud version
Section titled “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 (or -v) is also available and prints just the semver string for scripts.
zevcloud help [command]
Section titled “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.
Environment Variables
Section titled “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:
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
Section titled “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
Section titled “Exit Codes”| Code | Meaning |
|---|---|
0 | Success |
1 | Error (authentication, deployment failure, etc.) |