Build on another server
Build a project's image on a separate build server so heavy builds never slow production: set up a build server, choose Build on, and what happens to the image, the cache, cancels and failures.
By default a project is built on the server it runs on. A big next build, a Rust compile or a Buildpacks
run then competes with your live apps for CPU, memory and disk. Build on moves the build to another of
your servers: the image is built there and then sent to the deploy server, which only has to load it and
start the container.
Nothing else about the build changes. The same builder runs (Auto with Synq's generated Dockerfiles, your Dockerfile, Nixpacks, Railpack or Buildpacks), with the same settings, the same build log and the same Cancel button.
What you need first
- Two of your own servers with Docker, connected to Synq under Servers: the one the app runs on and the one that builds.
- The same CPU architecture on both (both amd64, or both arm64). An image built on an arm64 server does not start on an amd64 server.
- Permission to change the build server's settings and the project's settings.
Set up a build server
Turn on "Can build for other servers"
Open Servers, pick the server that should build, and open its Docker tab. Turn on Can build for other servers in the Build for other servers card. It is off for every server until you turn it on, so no server builds code for another one by surprise.
Choose it under Build on
Open the project, go to Configuration, and open the Build on card. Pick the build server instead of Deploy server, then Save. The deploy server itself is not listed: building there is the default.
Deploy
The setting applies from the next deploy. The build log says where the build runs, for example
→ Build server: builder-1 (amd64). The image is built there and shipped to the deploy server over SSH (zstd).
A compose or monorepo project uses the same card: every service image is built on the build server and sent to the deploy server as soon as it is ready, while the build server moves on to the next service.
What happens during a deploy
- Checks before anything is cloned. Synq connects to the build server and checks that it still builds for other servers, that Docker answers, that its CPU architecture matches the deploy server's, and that it has at least 2 GB of disk left for Docker.
- The build runs on the build server exactly like a build on the deploy server. Clone on the server, per-server GitHub access and forwarded git credentials apply to the build server, because that is where the source is fetched. Project variables reach the build as a BuildKit secret, never as an image layer or a command-line argument.
- The hand-off. Synq checks the image's CPU architecture and that the deploy server has room for it,
then streams
docker savefrom the build server intodocker loadon the deploy server through the SSH connections the panel already holds. The stream is compressed with zstd when both servers havezstd, otherwise gzip. Nothing is written to a temporary file, no registry is involved, and no port is opened on either server. - Verification. On the deploy server Synq inspects the loaded image and compares it with the one that was built: the same image ID, or, when the two Docker daemons use different image stores, the same layers, platform and container settings. An image that does not match is deleted and the deploy fails.
- Clean up. The image is removed from the build server. On the deploy server it carries the usual tag and labels, so rollbacks, the rollback window and image cleanup treat it like any other build.
The bytes travel from the build server to the machine running the panel and on to the deploy server. When the panel runs on your laptop (the desktop app), keep the image size in mind.
Build cache
The build cache stays on the build server: BuildKit's layer cache and the package-manager caches that Synq's generated Dockerfiles mount are reused by the next build of the project there. Clear build cache on a project that builds elsewhere clears the build server's cache. The daily build-cache sweep keeps every server's cache under 10 GB, build servers included.
A build server without the docker buildx plugin uses Docker's legacy builder, which keeps no cache between
remote builds (the image is removed after the hand-off) and cannot pass variables as secrets. Install
docker-buildx-plugin on build servers.
When the build server can't build
| Problem | What happens |
|---|---|
| The build server is offline, or Docker on it does not answer | The deploy fails before cloning: "Can't reach build server builder-1: ..." |
| "Can build for other servers" was turned off, or the server was removed | The deploy fails and names the setting. Removing a server sends its projects back to building on their deploy server. |
| The build server's CPU architecture differs from the deploy server's | The deploy fails: "The build server builder-1 builds arm64 images, but the deploy server runs on amd64". Synq does not cross-compile. |
| Less than 2 GB of free Docker disk on the build server | The deploy fails before the build. A build that runs out of disk midway says which server to clean up. |
| The deploy server has no room for the image | The transfer does not start, and the message gives both sizes. |
| The transfer breaks or stalls for 10 minutes | The deploy fails; the partial image is removed from the deploy server. |
To build on the deploy server instead of failing in the first four cases, turn on Build on the deploy server if this one is unavailable in the Build on card. The deploy log then says why it fell back. It is off by default: when you move builds off production, production should not start building on its own.
Cancelling
Cancel stops the build on the build server (its docker build and any build containers there) and stops
an image transfer that is under way. An image that was already loaded on the deploy server for the cancelled
deploy is removed again.
What always builds on the deploy server
- Static sites. Their files are extracted from the build container into the folder the edge serves, on the deploy server. In a compose project, static services build on the deploy server while the other services build on the build server.
- Projects that deploy a prebuilt image and rollbacks that restore a kept image build nothing.
- Apps that run directly on the host (without Docker), Synq Cloud projects and cluster projects, which have builders of their own.
- App templates with an inline Dockerfile (one-click apps that ship their own build files).
From the API
Turn a server into a build server, then point a project at it:
curl -X PATCH -H "Authorization: Bearer $SYNQ_TOKEN" -H "Content-Type: application/json" \
-d '{"buildServer":true}' \
"$SYNQ_URL/api/system/servers/$BUILD_SERVER_ID"
curl -X PATCH -H "Authorization: Bearer $SYNQ_TOKEN" -H "Content-Type: application/json" \
-d '{"buildServerId":"'"$BUILD_SERVER_ID"'","buildServerFallback":false}' \
"$SYNQ_URL/api/projects/$PROJECT_ID"Send "buildServerId":null to build on the deploy server again. The server must belong to the project's
organization and have buildServer on, or the request fails with 400.
Related guides
Build detection and builders
How Synq decides how to build your code (the Dockerfile-first rule, Compose, framework detection) and how to choose another builder per project, Dockerfile with a custom path and context, Nixpacks, Railpack or Cloud Native Buildpacks.
Compose & multi-service apps
Run an app that's really several pieces at once — web, worker, database — from a docker-compose file or added by hand, and keep every service in sync.