ZevCloud
Dashboard

Deployments

How Deploys Work

What happens between a git push and your app being live, what gets cached, and why a build takes the time it does.

Most deploy problems are easier to fix once you know which step they happened in. This page walks through what ZevCloud does between your push and your app answering requests.

The pipeline

push ──▶ match ──▶ clone ──▶ detect ──▶ build ──▶ start ──▶ route

1. Match. A push to your connected repository tells us which services to deploy. Only services on that repository and that branch are considered. If several services share one repository, we also compare the changed files against each service’s Root Directory, so a commit that only touches frontend/ doesn’t rebuild your API. Changes to shared files outside every service folder rebuild all of them.

2. Clone. We fetch that exact commit. If an image for this service already exists for the same commit, we skip straight to the start step — this is why redeploying an unchanged commit is near-instant.

3. Detect. We read your Root Directory and work out how to build it:

  • A Dockerfile there means you’ve already described your build, so we use it as-is. See Using a Dockerfile.
  • Otherwise we look for a manifest — package.json, requirements.txt, pyproject.toml, go.mod, Gemfile, composer.json — and hand the folder to Nixpacks, which works out the language, the system packages it needs, and how to install and start it. Its provider docs list exactly which files each language is detected by, which is the quickest way to check why your project was detected as one thing rather than another.

You can see the resolved plan at the top of any build log, including the detected language and the exact install and start commands.

4. Build. The plan runs in three phases:

PhaseWhat happensExample
SetupSystem packages your stack needsPython, Node, a compiler when a dependency requires one
InstallYour dependenciesnpm ci, pip install -r requirements.txt
BuildYour build command, if you have onenpm run build

5. Start. The new container runs your start command and has to answer on the configured Port before it receives traffic.

6. Route. Traffic moves to the new container and the previous one stops. Your domain and certificate carry over untouched.

Until step 6, your previous version keeps serving traffic. You can cancel a queued or running deploy at any point before then, and your app carries on serving that previous version.

If the build queue is momentarily full when you deploy, the deploy is refused with “The build queue is full right now. Try again in about N seconds.” Wait that long and deploy again.

What gets cached

Each phase is a layer, and layers are reused until something they depend on changes. Your source code is copied in last, so a code-only change reuses everything above it.

LayerRebuilt when
System packagesYour detected stack changes — a new dependency needs a compiler, you change runtime version
DependenciesYour manifest or lockfile changes
Your codeEvery commit (this is the cheap part)

The practical shape of this: the first build of a project is the slow one. A first build that takes several minutes is normal, and later builds of the same project are usually well under a minute. A build that’s slow every time means something is invalidating a layer on each run, and that’s worth looking at.

Why a build is slow

Work through these in order.

Is it only the first build?

Compare durations in the Deployments tab. First build slow, subsequent builds fast is the system working correctly — there’s nothing to fix.

Does a dependency compile from source?

This is the most common cause of a build that’s slow every time. Some packages ship only source code, so your build has to install a compiler and build them on every machine that hasn’t done it before. Swapping to a prebuilt equivalent is usually a one-line change:

SlowFastLanguage
psycopg2psycopg2-binaryPython
mysqlclientpymysqlPython
bcryptbcryptjsNode
node-sasssassNode
sharp pinned to an old versioncurrent sharpNode

psycopg2 is worth calling out: it pulls in a C compiler and PostgreSQL development headers before it can build, which adds several minutes on its own. psycopg2-binary is a drop-in replacement that installs in seconds, and both SQLAlchemy and Django accept it without any code change.

When you create a service, ZevCloud flags these in your manifest before you deploy.

Is your lockfile changing on every commit?

If your lockfile is regenerated or reformatted on each commit, the dependency layer can never be reused. Commit a stable lockfile and leave it alone between dependency changes.

Are you installing things you don’t need at runtime?

Browser automation tools (Puppeteer, Playwright, Cypress) download 100–200 MB of browsers on install. If they’re in devDependencies and your build doesn’t run tests, they’re pure cost. ZevCloud sets variables to skip those downloads by default on Node projects.

Is the build doing work your app doesn’t need?

Machine-learning frameworks (torch, tensorflow) are hundreds of megabytes. That’s a real cost you may need to pay, but it’s worth checking it’s actually imported.

Reading a failed build

Open Deployments → the failed deploy. Match the last thing in the log to a phase above:

Last thing you seePhaseUsually means
failed to detect the application typeDetectRoot Directory is wrong, or the folder has no recognised manifest
A package manager error, ERESOLVE, a compiler errorInstallA dependency problem — read the first error, not the last
Your own build command failingBuildReproduce locally with the same command
Build succeeded, deploy failed on health checksStartYour app isn’t answering on the configured Port
Deploy succeeded, every URL returns Bad GatewayRouteThe Port setting doesn’t match what your app listens on

The last two are the same root cause and are covered in detail under Troubleshooting.

Things that surprise people

Environment variables apply at build, not at restart. A variable change reaches your app on the next deploy. Restarting a running container won’t pick it up. The dashboard reminds you while you have unapplied changes.

A restart is not a redeploy. Restart reuses the existing image. Settings that affect how a container is built or routed — Port, build commands, variables — need a redeploy.

Build timeouts scale with your plan. A build that’s cut off mid-way is a timeout, not a crash. Limits are listed under Plans.

An app that keeps crashing on start is stopped. After 10 crashes in a row on start, the app is stopped automatically and the team owner is emailed. The dashboard shows why. Fix the cause (the logs show it) and redeploy, which clears the stop. See Crash-loop protection.

Rolling back is usually instant. Recent deployments whose build is still stored roll back without a rebuild. See Rollback.

The Root Directory is also the auto-deploy filter. Setting it to a subfolder means pushes that don’t touch that folder won’t deploy. That’s usually what you want, and occasionally surprising when you expect a deploy and don’t get one.

Updated at, Monday, October 26, 2026