Deployment
What happens when you push
Coolify watches the repository. A push to the default branch triggers a build, and a successful build replaces the running container.
git push
|
v
Coolify detects the commit
|
v
docker build using the Dockerfile in this repository
| VITE_ variables are passed as build arguments here
v
Health check the new container must answer before it receives traffic
|
v
Rolling replacement old container stops once the new one is healthyThe rolling replacement means a deployment does not normally cause downtime. A failed health check means the new container never receives traffic and the old one keeps serving, which is the behaviour you want when a build is broken.
The build stages
The Dockerfile has three stages, and the split exists for specific reasons.
deps installs production dependencies only. Keeping it separate means the runtime image never contains the development toolchain, and this layer is cached independently of the application source, so a code change does not reinstall dependencies.
build installs everything, copies the source, and runs the production build. This entire stage is discarded afterwards.
runtime starts from a slim Node image and copies in only the built output, the production dependencies, and the server entry point.
The result is roughly a third of the size of the single-stage image it replaced.
Build-time variables
Vite inlines VITE_ variables into the client bundle when the build runs, so they must be present as build arguments. The Dockerfile declares exactly three, and no more should be added.
This is where a security problem lives. When Coolify is told a variable is required at build time, it writes that variable into the generated build definition, which means its value appears in build logs and in the image's metadata. Marking a secret as build-time available publishes it to anyone who can read a build log.
The rule: only the three VITE_ variables are build-time. Everything else is runtime-only. If you add a variable, think about which side of that line it belongs on before you configure it.
The health check
The container is considered healthy when it answers an HTTP request locally, and the rolling replacement above depends on it: without a check there is nothing for Coolify to wait on, so a container that starts and immediately breaks still replaces a working one.
Configure it with 127.0.0.1 rather than localhost, or it will fail against a service that is working correctly. Health checks explains why, and lists the settings for both applications.
Two applications, one repository
This repository builds two separate Coolify applications: the alumni directory, and the documentation site you are reading, which is built from docs/Dockerfile and served by nginx.
They deploy independently, so a documentation change cannot break the application. What keeps them from rebuilding each other is the Watch paths setting: the documentation application watches docs/**, so it only rebuilds when documentation changes.
The application itself has no watch paths set, which means it rebuilds on every push, including documentation-only ones. That is a deliberate trade: scoping it would avoid some wasted builds, but a forgotten path would silently stop real changes from deploying, and a wasted no-op rolling update is cheaper than that.
Rolling back
Coolify keeps previous images and can redeploy one. That reverses an application regression quickly.
It does not reverse a database migration. If a deployment included a schema change, rolling the application back leaves the new schema in place, and the older application may not work against it. Migrations and application code are separate concerns with separate rollback paths, which is one reason to keep migrations additive where possible.
Known deployment behaviours
Long builds can disturb Coolify itself. During builds over ten minutes the dashboard sometimes loses its connection to Redis and returns an error. The application is unaffected. Restarting the Redis container clears it.
Build caches accumulate. Pruning old images and build caches periodically is necessary on a disk this size. Enabling Coolify's automated cleanup is the better fix.
There is no staging environment. Every deployment goes straight to production, in front of real members. Until that changes, the mitigations are careful review, a working health check, and keeping changes small enough to reason about.