How a deploy works
Detection, the build queue, the build, the start and the switch-over, and the rules your app must follow.
Push
Push to GitHub or run dock deploy in your folder.
Build
We detect your stack, install it and build an image.
Start
Your app starts next to the old version: no downtime.
Live
Traffic switches over. HTTPS is already on.
1. We detect your stack
We read the files at the root of your app (or the folder you chose) and pick the stack in this order:
| Your repository has | We build it as |
|---|---|
composer.json and artisan | Laravel |
@nestjs/core, next, nuxt, express, fastify, koa or hono in package.json | NestJS, Next.js, Nuxt, Express or Node.js |
react or vue in package.json (no server) | A static site built with Node.js |
Any other package.json | Node.js |
composer.json | PHP |
| Streamlit, Django, Flask or FastAPI in your Python dependencies | Streamlit, Django, Flask or FastAPI |
requirements.txt, pyproject.toml or Pipfile | Python |
go.mod | Go |
Gemfile (with rails → Ruby on Rails) | Ruby |
Dockerfile only | Docker |
index.html | Static site |
A Dockerfile always wins
If your repository has a Dockerfile, we build with it, whatever the stack. Delete it (or point the project to another folder) to use our build instead.
2. It waits in the build queue
Builds run one after another on each build server. While yours waits, the deploy page shows how many are ahead. Paid plans build sooner: Hobby and Pro have priority, Team goes first.
3. We build
We install your dependencies and run your build command (npm run build, composer install, pip install…), then package the result. The build log streams live on the deploy page and stays there.
Builds keep a warm cache per server, so the second build of the same app is usually much faster.
4. Your app starts
Your new version starts next to the running one. We wait until it answers, then switch traffic to it and stop the old one. If it never answers, the old version keeps running and the deploy fails with your app's last output.
Your app must follow three rules to start:
Listen on PORT
Read the PORT variable and listen on it. We set it for you; see the default ports below.
Listen on 0.0.0.0
Not localhost or 127.0.0.1: from outside the container those can't be reached. HOST=0.0.0.0 is set for you.
Start within 5 minutes
Most apps start in seconds. Large Java apps on small plans can take a couple of minutes, which is fine.
Which port
We route traffic to the first of these that exists:
- The Port you set in the project's Settings.
- A
PORTvariable you set yourself. - The port we saw your app listening on during an earlier deploy (we re-route to it automatically).
- The port your
Dockerfileexposes (EXPOSE 8000). - The stack's default: 5000 for Python, 8080 for PHP, Laravel and Go, 3000 for everything else. Static sites are served on 80 by nginx.
If your app listens on another port than expected, we notice, route to it and redeploy once on our own.
Zero downtime
Visitors keep using the old version during the whole deploy and the switch. If you set a Health check path in Settings (for example /health), we also wait for that path to answer with a 2xx or 3xx before switching.
What we refuse to build
- Database servers inside your image (MySQL, PostgreSQL, MongoDB… installed in your Dockerfile). They would lose their data on every deploy: use a managed database instead.
- Remote desktops (VNC, Openbox and similar).
