Dokploy builds run on the server that hosts your apps, with the CPU and memory it has. When a build is slow or dies, the log rarely says why: a Nixpacks or Dockerfile step just ends, sometimes with exit code 137 (the kernel killed it for memory), sometimes with a timeout, sometimes it simply takes five minutes instead of thirty seconds. This guide separates the three underlying problems, CPU contention, memory exhaustion and build cache misses, and gives the fixes in order of effort.
Diagnose in sixty seconds
Open an SSH session while a build runs and look at three things.
top -bn1 | head -5 # the "st" value: CPU steal
free -h # swap in use during the build?
dmesg -T | grep -i -E 'oom|killed process' | tail # kernel OOM kills
docker stats --no-stream # which container is eating RAM
- Steal above 5 to 10 percent and build times that vary a lot between runs: CPU contention on a shared host. Fixes 5 and 6.
- Swap filling, OOM lines in dmesg, exit code 137: memory exhaustion. Fixes 1, 2, 3 and 6.
- Consistently slow with low steal and free memory: the build is doing too much work every time. Fixes 3, 4 and 7.
Fix 1: cap the Node.js heap and other build-time memory hogs
Next.js, Nuxt, Vite and TypeScript builds allocate freely and the Node default heap can exceed the server. Set the heap explicitly as a build-time environment variable in Dokploy, sized to leave room for the running containers:
NODE_OPTIONS=--max-old-space-size=2048
On a 4 GB server 2 GB for the build is the ceiling; on 8 GB, 3 to 4 GB. For Python images avoid compiling wheels during the build (use pip install --only-binary=:all: where possible); for PHP, Composer's --no-dev --prefer-dist keeps memory down. Dokploy's Nixpacks and Railpack build types accept their own variables (NIXPACKS_BUILD_CMD, RAILPACK_BUILD_CMD) if you need to change the command.
Fix 2: add memory, or add swap as a stopgap
Builds need 500 MB to 2 GB over whatever the running services already use, and Dokploy itself holds about 400 MB. If free -h shows the server at the edge before a build starts, the honest fix is more RAM: the step from 4 GB to 8 GB (Starter to Growth on the Dokploy hosting page) ends most 137s. A 2 GB swap file stops the kernel killing builds outright, at the cost of slow builds while swapping:
fallocate -l 2G /swapfile && chmod 600 /swapfile && mkswap /swapfile && swapon /swapfile
echo '/swapfile none swap sw 0 0' >> /etc/fstab
Treat swap as a seat belt, not a plan: a server that swaps during every deploy is undersized.
Fix 3: stop rebuilding what has not changed
Most of a slow build is dependency installation. With the Dockerfile build type, copy the lock file and install dependencies in their own layer before copying the source, so Docker reuses the cached layer when only code changed; use multi-stage builds so the runtime image does not carry build tools. With Nixpacks or Railpack the detection does this reasonably, but a .dockerignore that excludes node_modules, .git and build output keeps the context small. Prefer the Dockerfile route for anything you deploy daily; our Next.js guide has a worked example that cuts the image from over 1 GB to about 200 MB.
Fix 4: keep the disk from filling
A disk near capacity slows every layer write and, past the edge, puts the Dokploy database into recovery mode. Check df -h and docker system df; prune with docker system prune -a and docker builder prune (keep some build cache, it is what makes Fix 3 work); enable Dokploy's scheduled cleanup. Budget 64 GB or more for a build server.
Fix 5: one build at a time, and move production off the box when it matters
Dokploy runs builds with a per-server concurrency of 1 by default (Settings, Deployments), which is right for a server that also serves traffic: two parallel builds double the memory spike. Do not raise it on the production machine. If the problem is that builds slow your live applications, the structural fix is to split them: a build server added under Remote Servers (type Build Server) clones, builds and pushes the image to a registry, and the production server only pulls and runs it. At the time of writing build servers work for Applications, not Compose services, and need Docker and a registry.
Fix 6: dedicated cores
If steal time is the diagnosis, no amount of tuning helps: your cores are being given to other tenants during exactly the seconds you need them. A representative Node.js multi-stage build on four shared vCPUs measured 35 seconds at best and 4 minutes 20 seconds at worst in our shared vs dedicated test; the same build on four dedicated cores stayed between 32 and 38 seconds. The Server Type toggle on the MassiveGRID configurator switches the Dokploy presets to dedicated cores ($19.80 for Starter, $39.60 for Growth) with the sliders unchanged.
Fix 7: fix DNS and network stalls inside builds
A build that hangs at npm ci, apt-get or pip install and finally fails with Could not resolve host is not a resource problem. The Dokploy docs trace it to host resolvers that fail inside build containers (Hetzner's defaults are the documented example) and fix it by giving Docker public resolvers:
echo '{"dns": ["1.1.1.1", "8.8.8.8"]}' | sudo tee /etc/docker/daemon.json
sudo systemctl restart docker
Merge the key into an existing daemon.json rather than overwriting it, and expect a short restart of every container, including Dokploy. Verify with docker run --rm alpine nslookup github.com.
What a right-sized Dokploy build setup looks like
- Occasional deploys of a few apps: Starter, 2 vCPU and 4 GB, with a 2 GB Node heap cap and a Dockerfile that caches dependencies.
- A team deploying several times a day: Growth on dedicated cores, 4 vCPU and 8 GB, concurrency left at 1.
- Builds that disturb production or a monorepo that takes minutes: a separate build server (the Enterprise preset, 16 vCPU and 32 GB, on dedicated cores) pushing to a registry, with production on Growth.
Frequently Asked Questions
What does exit code 137 mean in a Dokploy build?
The build process received SIGKILL, almost always from the kernel’s out-of-memory killer. Confirm with dmesg -T | grep -i oom. Fix by capping the build’s memory (NODE_OPTIONS=--max-old-space-size for Node projects), adding RAM, adding swap as a stopgap, and making sure only one build runs at a time.
Why is the same Dokploy build fast sometimes and slow other times?
That pattern is CPU steal on a shared host: your cores are shared with other tenants and the hypervisor throttles you when they are busy. Check the st column in top during a build. Dedicated cores remove the variance; a separate build server removes the impact on production.
Can I run Dokploy builds on a different server?
Yes. Add a server of type Build Server under Remote Servers, let Dokploy set it up, add a container registry under Settings, and enable the build server in the application’s Advanced tab. Dokploy builds there, pushes the image, and the production server pulls it. At the time of writing this works for Applications, not Compose services.
Builds that take the same time every run
Switch the Dokploy presets on the MassiveGRID configurator to dedicated cores: Starter (2 vCPU, 4 GB) for $19.80 a month, Growth (4 vCPU, 8 GB) for $39.60, or the 16 vCPU Enterprise preset as a build server. Proxmox HA failover, Ceph NVMe storage, 100% uptime SLA, 15-day money back, and we install Dokploy on request.
Configure a Dokploy server