ZevCloud
Dashboard

Deployments

Web Applications

Deploy web applications from a Git repository. ZevCloud supports any language or framework that can run in a container.

Supported Frameworks

ZevCloud uses Nixpacks to auto-detect and build your application:

FrameworkAuto-DetectedDefault Port
Next.js✅3000
React / Vue (Vite)✅Served as a static site (no port)
Express / Node.js✅3000
NestJS✅3000
FastAPI✅8000
Django / Flask✅8000
Go✅8080
Ruby on Rails✅3000
PHP / Laravel✅8000
Rust✅8080
Static HTML✅80

Deploying from GitHub

Public Repositories

  1. Add Service → Web Application → Public Repository
  2. Paste the repository URL (e.g., https://github.com/user/repo)
  3. Select the branch
  4. Configure and deploy

Private Repositories

  1. Add Service → Web Application → Import from GitHub
  2. If not connected, click “Connect GitHub” to install the ZevCloud GitHub App
  3. Select your repository from the list
  4. Select the branch
  5. Configure and deploy

Build Configuration

ZevCloud auto-detects most settings, but you can customize:

SettingDescriptionExample
Build CommandCommand to build your appnpm run build
Install CommandCommand to install dependenciesnpm ci
Start CommandCommand to start your appnpm start
Output DirectoryFor static buildsdist, .next, build
Root DirectoryIf your app is in a subdirectorypackages/web
PortPort your app listens on3000

These can be set during creation or updated in Service Settings. Root and output directories can be written with or without a leading slash: dist and /dist mean the same folder. Root Directory is a dropdown of the folders in your repository, so you pick the path rather than typing it — a mistyped one fails the build several minutes in, with an error about the build tool rather than the path.

If your repository has its own Dockerfile, ZevCloud uses it instead of building your app automatically. See Using a Dockerfile.

Command rules

Install, build and start commands can chain steps with && or ||, for example npm ci && npm run build. They can’t contain:

  • ;, a single | or a single &
  • redirects (> or <)
  • backticks or parentheses
  • $VARIABLES outside single quotes

If a step needs any of these, put the logic in a script (for example a start script in package.json) and run that script as the command. Saving a command that breaks these rules fails with an error naming the character, such as “Your start command can’t contain …”.

Your app still sees every environment variable at runtime. Read them in your code (for example process.env.PORT) rather than in the command.

Static Sites & SPAs

Client-rendered apps (Vite, React, Vue, plain HTML) don’t need a server process. Their build produces a folder of static files — the right way to serve them is as a static site.

When you create a service from a Vite project, ZevCloud detects this and pre-selects static serving. You can also change it any time in Service Settings → Build & Deploy:

SettingWhat it does
Static siteBuilds your app, then serves the output folder as files. No server process, no port to configure.
SPA (Single Page Application)Serves index.html for unmatched routes, so client-side routing (React Router, Vue Router) works on page refresh and direct links.
Publish DirectoryThe folder your build produces. Vite uses dist; Create React App uses build.

Common symptoms and their fix:

  • Deploy succeeds but the site is blank or 404s — the Publish Directory doesn’t match your build output. Check what folder your build command creates.
  • Pages 404 on refresh or direct links — enable the SPA toggle so unmatched routes fall back to index.html.
  • Deploy fails with a port or health check error on a Vite/React app — enable Static site. A client-rendered app has no server listening on a port, so port-based deploys can’t succeed.

Changes take effect on the next deploy — the dashboard offers a redeploy when you save.

Monorepos

Create one service per app. How you point each service at its app depends on whether the repository is a workspace.

Independent folders

If each app has its own package.json (or requirements.txt, go.mod) and they don’t depend on each other, set each service’s Root Directory to its folder:

repo/
  frontend/    → service 1, Root Directory: frontend
  backend/     → service 2, Root Directory: backend

Nothing else to configure. This is the common case.

Workspaces (pnpm, Yarn, npm, Turborepo, Nx)

If your repository has a turbo.json, a pnpm-workspace.yaml, an nx.json, or a workspaces field in the root package.json, the apps share dependencies through the repository root. Pointing the Root Directory at the app folder will fail the install, because dependencies declared as workspace:* can only be resolved from the root.

Leave the Root Directory at / and filter the build to one app instead:

# pnpm + Turborepo
pnpm install --frozen-lockfile
pnpm turbo run build --filter=web...
pnpm --filter web start

# npm workspaces
npm ci
npm run build --workspace=web
npm start --workspace=web

# Yarn workspaces
yarn install
yarn workspace web build
yarn workspace web start

The trailing ... in a Turborepo filter builds that app’s own workspace dependencies first. Without it, shared packages the app imports won’t be built.

When you select a repository, ZevCloud detects the workspace and offers these commands filled in with your package name — one click applies them.

Auto-deploy is folder-aware

For services with a Root Directory set, pushes only redeploy the services whose folder contains changed files. A commit that only touches frontend/ won’t rebuild your backend. Changes to shared files outside every service folder — a root package.json, a shared packages/ directory — redeploy all services from that repository, since they can affect any build.

Environment Variables

Set environment variables in the Variables tab of your service:

DATABASE_URL=postgres://user:pass@host:5432/db
NODE_ENV=production
API_KEY=sk_live_...

Variables marked as secret are encrypted at rest and hidden in the UI.

Auto-Deploy on Push

When you push to the configured branch, ZevCloud automatically:

  1. Receives a GitHub webhook
  2. Clones the latest code
  3. Builds using Nixpacks
  4. Deploys with zero-downtime rollout
  5. Sends an email notification (success or failure)

Disable auto-deploy in Service Settings → Build & Deploy.

Build Logs

View real-time build logs in the Deployments tab. Each deployment shows:

  • Git commit message and SHA
  • Build duration
  • Success or failure status
  • Detailed build output

How Deploys Work explains each build phase, what’s cached between deploys, and how to read a failed build back to the step it failed in.

Resource Limits

Each plan provides different resource limits:

PlanMemoryCPUBuild Timeout
Free512 MB1 core10 min
Starter2 GB1 core20 min
Pro4 GB2 cores30 min
Business8 GB4 cores60 min

Persistent volumes (beta)

A deploy builds a fresh container from your code, so anything your app wrote to its own filesystem is gone after the next deploy or restart. That is the right default for code, and the wrong one for data: SQLite files, user uploads, generated reports, a local cache you want to keep.

A persistent volume is a folder that survives deploys and restarts. You pick the path inside the container, and whatever your app writes there stays.

To attach one: open the service, go to the Volumes tab, enter the folder your app writes to (for example /app/data or /app/uploads) and click Attach volume. The service restarts once so the folder is mounted. From then on every deploy and restart finds the same files there.

A few things to know:

  • Paid plans only. Each plan includes a total allowance in GB across all volumes on one service. The Volumes tab shows how much is used; we email you when a service gets close to its allowance, and the dashboard turns amber at 80%. Nothing is paused when you reach it, but writes fail once the disk is actually full, so give yourself room.
  • Up to three volumes per service. One for data and one for uploads covers most apps. Mount paths cannot overlap.
  • The mount hides what was there. An empty volume mounted at /app/data covers any /app/data that came from the build. Mount at a folder your app creates at runtime, not one that ships in your repository. You cannot mount over /app itself or the container’s system folders.
  • Removing a volume deletes its files. There is no undo, and the service restarts afterwards. Download anything you need first (the Terminal tab can tar a folder, or your app can export it).
  • One service, one volume. Volumes are not shared between services. If two services need the same files, use a storage bucket instead.

Outbound network restrictions

To keep the platform clean for everyone, customer containers are not allowed to make outbound connections on a few specific ports. The host blocks them at the firewall, so any code in your app that tries to reach these ports will time out.

  • SMTP (25, 465, 587, 2525) — direct mail submission. Use a transactional email API (Resend, Mailgun, Postmark, SendGrid) over HTTPS instead. Their REST/HTTP endpoints are not blocked.
  • IRC (6667, 6697) — typical command-and-control channels.
  • Mining-pool stratum (3333, 4444, 5555, 7777, 14444) and Bitcoin RPC (8332, 8333).

Everything else (HTTPS to third-party APIs, your database, Redis, CDNs, webhooks) works normally. If you need to send email, switch to your provider’s HTTPS API.

Rollback

If a deploy causes problems, roll back to an earlier one from the Deployments tab.

  • Instant rollback. Recent deployments whose build is still stored roll back instantly. Nothing is rebuilt: the stored build starts again, usually within seconds.
  • Older deployments. Older builds may no longer be stored. Apps built with a Dockerfile rebuild the old commit instead, which takes as long as a normal build. Other apps can’t roll back that far: push a revert commit to the branch and let it deploy.

Cancelling a build

A queued or running deployment can be cancelled from the Deployments tab. Your app keeps serving its previous version, so cancelling is safe at any point.

Crash-loop protection

If your app crashes 10 times in a row while starting, ZevCloud stops it automatically and emails the team owner. The dashboard shows why the app was stopped.

To recover, find the cause in the Logs tab (it is usually the last few lines before each crash), fix it, and redeploy. A successful redeploy clears the stop.

Updated at, Monday, October 26, 2026