Skip to main content

Dokploy Restarts the Container, Coolify Rebuilds It: What 30-120 Second Rebuilds Cost a Production Deploy Loop

9 min readDora NodaDora Noda
Share
On this page

You rotate a leaked API key. Ten services share it, so you update one environment variable in ten places and hit restart ten times. On one self-hosted panel, every service is back in seconds. On the other, each "restart" quietly becomes a full image rebuild — 30 to 120 seconds per app — and your five-minute rotation turns into twenty minutes of watching build logs. Nothing failed. No feature matrix warned you. The two buttons just mean different things.

That split comes from a head-to-head that tested Coolify v4.0 and Dokploy on identical Hetzner boxes for seven days with identical apps: in Dokploy, stopping and restarting a container restarts the existing image in place — no rebuild, no re-pull — while in Coolify v4.0, certain config changes (particularly environment variable edits in some deployment types) trigger a full rebuild from scratch at 30–120 seconds per app for production builds. The table below prices that difference across the three loops a production team actually runs; the rest of this post maps exactly which button does what on each panel, why rebuild-on-config-edit exists at all, and what a git-push PaaS owes its own config-edit path.

Production loopDokploy restart pathCoolify rebuild path
One env edit, one appSeconds (existing image restarts in place)30–120 s full rebuild, depending on app and cache
Secret rotation across 10 servicesUnder ~2 minutes, mostly clicking5–20 minutes of sequential rebuilds
Two config edits a week for a year (104 edits)~15–20 minutes of waiting, total~1–3.5 hours of waiting, total

The yearly row is the one that matters. Production teams edit config far more often than they ship code — key rotations, feature flags, log levels, endpoint URLs — so a per-edit tax compounds into hours while a restart stays linear and small. And the two builders cost the same: the same head-to-head timed a Next.js build at 87 seconds on Coolify versus 91 on Dokploy, within margin of error. The question was never which panel builds faster. It is whether a config edit pays the build toll at all.

What each button actually does​

Both panels expose similar verbs — restart, redeploy, rebuild — and both punish you for assuming they are synonyms. Here is the actual mapping, confirmed against each project's docs, issues, and CLI references.

On Dokploy, restart is stop-then-start of the existing container: no rebuild, no new image. The unofficial Dokploy CLI documents it exactly that way ("stop then start the service (no rebuild)"), and Dokploy's own operator guidance is explicit that restart does not pick up new code — content still stale after a restart needs a redeploy. Redeploy rebuilds from current source, and rebuild goes further, discarding build cache (and potentially interrupting the running container). One more Dokploy gotcha worth knowing: saving an env change does not restart anything by itself — you must redeploy or reload afterward for the new value to take effect.

On Coolify, the split is Restart versus Redeploy. Editing an environment variable never auto-redeploys; after saving, you choose. Restart is the runtime-only path — fine when the variable is read at process start. Redeploy is the full path, and for Dockerfile-built apps it triggers a complete rebuild: a known behavior tracked upstream as issue #2745. The practical rule operators converge on: Restart for runtime-only vars, Redeploy for build-time vars (anything like VITE_* baked into the bundle) or Dockerfile-built apps — where you pay the rebuild whether you wanted it or not.

Neither panel is innocent here, which is worth saying plainly. Dokploy itself had to rename its Compose "Reload" action to "Rebuild" (PR #4847) because users expected a lightweight container reload and got a full compose redeployment instead — the same trap, mirrored. And independent timed runs back up the shape of the gap: one operator deploying real apps on both panels measured redeploy cycles of 1–2 minutes on Dokploy versus 4–6 on Coolify for one app, and 3–4 versus 4–6 for another. The rebuild path is not a rounding error; on some apps it multiplies the cycle several-fold.


Why rebuild-on-config-edit exists at all​

It is tempting to file this as a Coolify bug, but the mechanism underneath is principled — it is just principled in a way that taxes the common case. Some environment variables genuinely must trigger a rebuild: anything consumed at build time is baked into the artifact. A VITE_API_URL change without a rebuild produces a new container running the old URL, which is worse than slow — it is wrong. The immutable-rebuild doctrine says the only safe response to any input change is a fresh image, and for build-time inputs that doctrine is exactly right.

The trouble starts when the doctrine gets applied to inputs it cannot see. A panel that cannot distinguish build-time from runtime variables has two choices: rebuild on every env edit (always correct, often slow) or restart on every env edit (always fast, sometimes wrong). Coolify's v4.0 behavior is the first choice leaking through on deployment types where the distinction is not wired up; Dokploy's restart is the second choice, with correctness delegated to the operator pressing the right button. Both are coherent. Only one of them bills you 30–120 seconds for changing LOG_LEVEL.

That is why the build cache is the real variable in this story, not the builder. Immutable rebuilds are cheap if and only if the cache makes them cheap: an untouched Dockerfile with warm layers rebuilds in seconds, while a cold cache (fresh box, pruned builder, cache-busting early layer) pays the full 87-or-91-second Next.js toll plus image push and container swap. The head-to-head's 30–120 second range is really a cache-warmth range wearing a per-app costume. Any team evaluating these panels should read it that way — and should test its own apps, on its own box, with its own cache state, before assuming its edits land at the cheap end. The r/coolify comparison thread from March 2026, where unexpected rebuilds after simple config changes were the top complaint, reads in hindsight as dozens of teams discovering their cache state the expensive way.

The honest caveats​

Four corrections before anyone pastes the table above into a decision doc.

First, the source comparison's hardware label needs a parenthetical: it calls its test box a "$5 Hetzner CCX13," but CCX13 (2 dedicated vCPU, 8 GB RAM, 80 GB NVMe) is not a $5 product — that price belongs to Hetzner's shared-CPU CX/CPX line. The specs are CCX13-class; the price tag is not. The restart-vs-rebuild finding does not depend on which tier the box actually was, but the budget line in your migration doc should use real list prices.

Second, Coolify v4.0 fixed some rebuild cases and not others. The head-to-head notes the dashboard resolved several of the March complaint-thread cases at launch while leaving other deployment types still rebuilding. Treat "Coolify rebuilds on env edits" as version- and deployment-type-specific, verify your exact setup (Nixpacks vs Dockerfile vs Compose behave differently), and re-test after upgrades — this is the fastest-moving cell in the whole comparison.

Third, rebuild semantics are sometimes the right call, and a panel that always restarted would be the worse tool. Build-time variables, Dockerfile edits, and base-image bumps should rebuild; silently restarting there ships stale artifacts with fresh labels. Judge a panel not by whether it ever rebuilds on config change, but by whether it rebuilds only when a build input changed.

Fourth, keep the scope of the finding in view. Both tools are single-box Docker panels — 0.8 GB versus 1.2 GB idle RAM on an 8 GB VPS is the headline resource gap, and both install in under five minutes. Restart-vs-rebuild decides your Tuesday afternoons, not your architecture. The questions these panels cannot answer for you — what happens on a second machine, who provisions it, what declarative fleet lifecycle looks like — are a different post (this blog has a whole shelf of them: the Dokploy-vs-Coolify single-box ceiling is well covered ground).

What a git-push PaaS owes its config-edit path​

Step back from the two panels and the design requirement is crisp. A deploy platform has exactly two legitimate responses to a config edit, and it must pick per edit, not per panel philosophy:

  1. Only runtime inputs changed → recreate the container from the same image with the new env. Seconds, no build queue, no cache lottery. This must be the default path, one click, obviously named.
  2. A build input changed → rebuild, and say so. Name the triggering input in the UI ("rebuilding: VITE_API_URL is a build-time variable"), so the wait reads as causality rather than superstition.

Everything else is commentary. Warm build caches, layer caching across apps, and fast builders compress the cost of path 2 but never remove the need to choose correctly — a 90-second builder that rebuilds when it should restart still loses to a 90-second builder that restarts, ten times out of ten, on a rotation night.

The symptom of getting this wrong is unmistakable and the head-to-head names its endpoint: tenants learn to batch env changes out of superstition. They queue up five unrelated config edits for one maintenance window, not because the changes are related but because each one might cost two minutes of build logs. That batching is pure process scar tissue — it slows incident response (the key rotation waits for the window), couples unrelated changes (the flag flip rides along with the endpoint migration), and teaches every new hire that config is scary. A platform whose config path is fast and legible never grows that scar: edits stay small, frequent, and boring, which is precisely what config edits should be.

So the next time a feature matrix tells you two panels both "support environment variables," ask the follow-up the matrix cannot encode: what exactly happens, in seconds and in build-queue depth, when I change one? The answer is the difference between a rotation that takes a coffee break and one that takes a lunch break — and it is worth more than most of the checkboxes above it.

Bex.co is the open-source, AI-native Render alternative — push a git repo, get a running HTTPS service on machines you own. Star the repo on GitHub or deploy your first app today.

Related articles

Run this on infrastructure you own

bex is the open-source, AI-native Render alternative — push a git repo and get a running HTTPS service on your own machines.

Get started with bex