Skip to content

Comments

feat: buildServerId + Docker image support for preview deployments#3784

Draft
kopandante wants to merge 2 commits intoDokploy:canaryfrom
kopandante:feat/preview-docker-image-and-build-server
Draft

feat: buildServerId + Docker image support for preview deployments#3784
kopandante wants to merge 2 commits intoDokploy:canaryfrom
kopandante:feat/preview-docker-image-and-build-server

Conversation

@kopandante
Copy link

@kopandante kopandante commented Feb 23, 2026

Problem

Preview deployments fail when using a separate build server (buildServerId != serverId) with a build registry.

Both deployPreviewApplication and rebuildPreviewApplication unconditionally null buildRegistry:

application.buildRegistry = null;

This breaks the entire image delivery pipeline:

  1. getBuildCommand() skips uploadImageRemoteCommand() — image never pushed to registry
  2. getImageName() returns local name (appName:latest) instead of registry tag
  3. getAuthConfig() returns undefined — no auth for Docker Swarm to pull

Regular deployApplication works correctly because it never nulls buildRegistry.

Fix

application.ts: Only null buildRegistry when there's no separate build server:

if (!application.buildServerId || application.buildServerId === application.serverId) {
    application.buildRegistry = null;
}

This preserves the original behavior for same-server deployments while enabling the registry pipeline for external build servers — matching exactly how deployApplication handles it.

builders/index.ts: Fix createService auth in mechanizeDockerContainer:

// Before: auth not extracted by dockerode with single-arg call
await docker.createService(settings);

// After: explicit auth parameter (matches dockerode's two-arg signature)
await docker.createService(settings.authconfig, settings);

service.update() auto-extracts opts.authconfig, but createService() does not when called with a single argument — this is an existing dockerode inconsistency.

Test plan

  • Preview deployment with buildServerId different from serverId and buildRegistry configured
  • Preview deployment without build server (same-server) — should behave as before
  • Regular (non-preview) deployment — no changes in code path

…ments

Preview deployments now correctly use `buildServerId` (falling back to
`serverId`) for build execution, log paths and deployment records --
matching the existing production `deployApplication` behavior.

Additionally, preview deployments can now be created from pre-built
Docker images via the new `deployFromImage` tRPC procedure, enabling
external CI/CD pipelines (GitHub Actions, etc.) to push images and
trigger preview deployments without building on the Dokploy server.

Changes:
- deployment.ts: resolve buildServerId for paths/exec/record
- application.ts: handle docker sourceType in deploy/rebuild preview
- preview-deployment.ts: extract preparePreview/insertAndConfigurePreview
  helpers, add createPreviewDeploymentFromImage
- preview-deployments schema: add dockerImage column and Zod schema
- router: add deployFromImage procedure with auth + BullMQ queue
Copy link
Contributor

@greptile-apps greptile-apps bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

5 files reviewed, 1 comment

Edit Code Review Agent Settings | Greptile

Comment on lines 168 to 172
await removeLastTenDeployments(
deployment.previewDeploymentId,
"previewDeployment",
previewDeployment?.application?.serverId,
);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

still passing application.serverId instead of buildServerId to cleanup old logs

Suggested change
await removeLastTenDeployments(
deployment.previewDeploymentId,
"previewDeployment",
previewDeployment?.application?.serverId,
);
await removeLastTenDeployments(
deployment.previewDeploymentId,
"previewDeployment",
buildServerId,
);

…ld server

When an application uses a separate build server (buildServerId != serverId),
the build registry is needed to push the built image so the deploy server
can pull it. Preview deployments were unconditionally nulling buildRegistry,
which broke the image push and Swarm auth for external build server setups.

Now buildRegistry is only nulled when there is no separate build server
(matching how regular deployApplication works).

Also fix dockerode createService auth: pass authconfig as first argument
since createService(opts) doesn't auto-extract it (unlike service.update).
@kopandante kopandante force-pushed the feat/preview-docker-image-and-build-server branch from 4bd5bb4 to 23fcb37 Compare February 24, 2026 04:09
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant