How the image is built
The platform builds your application's image from a Dockerfile in the deployed folder. It is the only build path today, and the interface says so rather than offering fields that change nothing.
What Zero expects from the repository
| Item | Rule |
|---|---|
Dockerfile | At the root of the deployed folder. Without it, the deployment fails at Building |
| Folder | The one the service declares inside the project's repository. Left blank, the repository root |
| Branch or tag | The one in the project's source, or the one given for that deployment |
| Port | The application must listen on 0.0.0.0, on the port given by the PORT variable |
What the platform does not do
- It does not detect frameworks. There is no "we detected Node and configured it for you".
- It does not run buildpacks. There is no build without a
Dockerfile. - It accepts no configurable build command. What builds is the
Dockerfile.
This is stated here and on the screen itself, because a form with those fields would create the expectation that filling them in changes something.
A minimal Dockerfile that works
FROM node:22-alpine
WORKDIR /app
COPY package*.json ./
RUN npm ci --omit=dev
COPY . .
# The platform supplies PORT (default 8080). The server reads process.env.PORT
# and listens on 0.0.0.0. EXPOSE does not change the port, and USER is not needed.
CMD ["node", "server.js"]
What most often makes a deployment fail after the build is the port: the application has to read PORT from the environment and listen on 0.0.0.0, rather than hard-coding a number the platform does not know about. EXPOSE in the Dockerfile does not set the port.
How the application runs
The platform runs every service under the same contract, whatever the image:
| Item | What it is |
|---|---|
| User | Always non-root, with numeric UID and GID 10001, whatever the image's USER |
| File system | Read-only, except /tmp |
/tmp | Writable, with a 512 MiB limit |
HOME | Points to /tmp |
| Port | The platform supplies the PORT variable with the service's port — default 8080. Listen on 0.0.0.0 on that port |
| Ready | The instance accepts TCP connections on the service's port |
Practical consequences:
- The image does not need to declare
USER. An image withoutUSER— like most official language images,node:18-alpinefor example — and an image withUSERby name, such asUSER node, work without changes. - Temporary files and caches go in
/tmp. The rest of the file system does not accept writes while the application runs. - The readiness check is TCP, not HTTP. The platform does not know which path your application answers, so it does not ask for one: accepting connections on the port is enough.
- Frameworks that follow the
PORTconvention work with no configuration — Express and Node withprocess.env.PORT,serve, gunicorn, Rails, Spring withserver.port=${PORT}.
When the application does not become ready, the deployment fails with the reason and the previous version keeps answering. See Deployment states.
Monorepo
Each service declares the folder it builds inside the project's repository — apps/api, for example. When creating the project, that is the Folder inside the repository field. The build happens from there, and that is where the Dockerfile has to be.
The declared folder carries over to every later deployment. A deployment that omitted it would look for the Dockerfile at the root of a repository that keeps it somewhere else.
The build log
The builder's full output is recorded in both outcomes — success and failure. Recording only on failure would be the obvious and wrong choice: someone investigating a slow build, or one that produced the wrong image, needs the log of a build that succeeded.
You find it under Logs → Build, choosing the deployment. Credentials appearing in the output are protected before it is stored.
The artifact
The build's result is an immutable artifact, identified by a unique fingerprint. It is never rebuilt in order to be reused: promoting a version to another environment reuses exactly the same artifact. See How a deployment works.
Common errors
| Symptom | Cause | What to do |
|---|---|---|
Dockerfile: no such file or directory in the build log | The deployed folder has no Dockerfile | Fix the service's folder |
| Authentication failure fetching the code | Private repository with no access token | Enter a token under Source, in the project |
| The build passes and the deployment fails with "The application started but did not answer" | The application does not listen on 0.0.0.0 on the PORT port — it listens on localhost or on a fixed port, for example | Read the port from PORT and listen on 0.0.0.0 |
| The build passes and the deployment fails with "The application stopped right after starting" | The application exits at startup — a missing variable, an unconfigured dependency, or a write outside /tmp | Look at the last lines under Logs → Runtime |
| Dependency error during the build | A difference between your machine and a clean build | Pin versions; the build does not reuse what exists on your machine |
Next steps
Was this page helpful?
Report a problem on this pageDo not send passwords, keys, tokens, or customer data.