Skip to content

Comments

feat: support Docker image source for preview deployments#3782

Closed
kopandante wants to merge 1 commit intoDokploy:canaryfrom
kopandante:feat/docker-image-preview
Closed

feat: support Docker image source for preview deployments#3782
kopandante wants to merge 1 commit intoDokploy:canaryfrom
kopandante:feat/docker-image-preview

Conversation

@kopandante
Copy link

@kopandante kopandante commented Feb 23, 2026

Problem

Preview deployments currently only work with sourceType: "github". Applications using Docker images (sourceType: "docker") have their preview builds silently skipped. Additionally, there is no way for external CI/CD pipelines (GitHub Actions, GitLab CI, etc.) to trigger preview deployments with pre-built Docker images.

This means users who want to offload builds to CI/CD runners -- or who use Docker image registries as their deployment source -- cannot use preview deployments at all.

Related issues: #2386, #1365

Solution

1. Docker source type support in preview deploy/rebuild

deployPreviewApplication() now handles sourceType === "docker" alongside the existing "github" branch:

if (application.sourceType === "github") {
  // existing: clone + build
} else if (application.sourceType === "docker") {
  // new: docker pull (via buildRemoteDocker)
}

Same pattern added to rebuildPreviewApplication().

Both functions also include the buildServerId fix from #3781.

2. Per-preview Docker image override

New dockerImage column on preview_deployments table allows each preview to use a different Docker image tag (e.g., ghcr.io/org/app:pr-42), independent of the parent application's dockerImage.

3. New API endpoint: previewDeployment.deployFromImage

New tRPC procedure that enables external CI/CD to trigger preview deployments:

// Input
{
  applicationId: string;   // required
  dockerImage: string;     // required (e.g., "ghcr.io/org/app:pr-42")
  pullRequestNumber?: string;  // optional: enables PR comment
  pullRequestTitle?: string;
  pullRequestURL?: string;
}

// Output
{
  previewDeploymentId: string;
  previewDomain: string;   // e.g., "https://preview-myapp-abc123.traefik.me"
}

The function:

  • Creates a preview deployment record with domain and Traefik configuration
  • Optionally posts a GitHub PR comment if a GitHub provider is configured and PR number is provided
  • Queues the deployment job (docker pull + mechanize container)
  • Returns the preview URL immediately

Example GitHub Actions workflow

on:
  pull_request:
    types: [opened, synchronize]

jobs:
  preview:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: docker/login-action@v3
        with:
          registry: ghcr.io
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}
      - uses: docker/build-push-action@v5
        with:
          push: true
          tags: ghcr.io/${{ github.repository }}:pr-${{ github.event.pull_request.number }}
      - name: Deploy preview
        run: |
          curl -X POST "${{ secrets.DOKPLOY_URL }}/api/trpc/previewDeployment.deployFromImage" \
            -H "x-api-key: ${{ secrets.DOKPLOY_API_KEY }}" \
            -H "Content-Type: application/json" \
            -d '{
              "json": {
                "applicationId": "...",
                "dockerImage": "ghcr.io/${{ github.repository }}:pr-${{ github.event.pull_request.number }}",
                "pullRequestNumber": "${{ github.event.pull_request.number }}",
                "pullRequestTitle": "${{ github.event.pull_request.title }}"
              }
            }'

Changes

File Change
packages/server/src/db/schema/preview-deployments.ts Add dockerImage column, new apiCreatePreviewDeploymentFromImage Zod schema
packages/server/src/services/application.ts Handle docker sourceType in deployPreviewApplication and rebuildPreviewApplication, include buildServerId fix
packages/server/src/services/preview-deployment.ts New createPreviewDeploymentFromImage() function
apps/dokploy/server/api/routers/preview-deployment.ts New deployFromImage tRPC procedure

Behavior

  • Docker source applications: preview deployments now work (previously silently skipped)
  • GitHub source applications: no change to existing behavior
  • External CI/CD: can trigger preview deployments via deployFromImage API
  • PR comments: optional -- posted when GitHub provider is configured and PR number is provided
  • Cleanup: existing PR close webhook handles preview cleanup as before

Testing

Tested on a Dokploy v0.27.0 instance with Docker source type applications and GitHub Actions triggered previews.

Greptile Summary

Added Docker image source support for preview deployments, enabling external CI/CD pipelines to trigger previews with pre-built images. Also includes buildServerId fix for remote builds.

Critical Issue Found:

  • Docker-based preview deployments will crash when GitHub is not configured because deployPreviewApplication() and rebuildPreviewApplication() unconditionally call GitHub comment APIs (issueCommentExists(), updateIssueComment()), which throw errors when githubId is empty

Changes:

  • Added dockerImage column to preview_deployments table for per-preview Docker image overrides
  • Extended deployPreviewApplication() and rebuildPreviewApplication() to handle sourceType === "docker" via buildRemoteDocker()
  • New createPreviewDeploymentFromImage() service function with optional GitHub comment support
  • New deployFromImage tRPC endpoint for API-triggered preview deployments
  • Included buildServerId fix from fix: use buildServerId for preview deployments #3781

Missing:

  • No database migration file for the new dockerImage column (need to run pnpm migration:generate)
  • All GitHub comment operations in deployPreviewApplication() and rebuildPreviewApplication() must be wrapped in if (application?.githubId) checks to prevent crashes for Docker-only applications

Confidence Score: 1/5

  • This PR will cause deployments to crash for Docker-based applications without GitHub configuration
  • The core functionality is well-designed, but there's a critical bug that will break the main use case: Docker-based preview deployments always attempt to update GitHub comments even when GitHub isn't configured, causing findGithubById("") to throw NOT_FOUND errors and crash the deployment. This affects both deployPreviewApplication() and rebuildPreviewApplication() functions in 6+ locations.
  • Pay close attention to packages/server/src/services/application.ts - all GitHub comment operations need conditional checks before the PR can be safely merged

Last reviewed commit: d37ab6c

(3/5) Reply to the agent's comments like "Can you suggest a fix for this @greptileai?" or ask follow-up questions!

Adds the ability to deploy preview environments from pre-built Docker
images, enabling external CI/CD pipelines (e.g., GitHub Actions) to
build images and trigger preview deployments via API.

Schema:
- Add `dockerImage` column to `preview_deployments` table
- Add `apiCreatePreviewDeploymentFromImage` Zod schema

Deploy logic:
- `deployPreviewApplication`: add `sourceType === "docker"` branch
  alongside existing GitHub branch. Uses `buildRemoteDocker()` (docker
  pull) + `mechanizeDockerContainer()`. Also includes buildServerId fix.
- `rebuildPreviewApplication`: same docker branch + buildServerId fix

Service:
- New `createPreviewDeploymentFromImage()` function that creates a
  preview deployment from a Docker image without requiring GitHub PR
  context. Optionally posts a PR comment if GitHub provider and PR
  number are provided.

Router:
- New `deployFromImage` tRPC procedure that validates permissions,
  creates the preview deployment, and queues the deployment job.
  Returns `previewDeploymentId` and `previewDomain`.

Workflow:
  GitHub Actions builds image -> pushes to GHCR ->
  calls Dokploy API `previewDeployment.deployFromImage` ->
  Dokploy pulls image and creates preview container with domain

Closes Dokploy#2386
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.

4 files reviewed, 6 comments

Edit Code Review Agent Settings | Greptile

@greptile-apps
Copy link
Contributor

greptile-apps bot commented Feb 23, 2026

Additional Comments (6)

packages/server/src/services/application.ts
deployment will fail for Docker-based apps without GitHub configuration

when application.githubId is empty (docker-only apps), issueCommentExists() calls findGithubById("") which throws a NOT_FOUND error, crashing the deployment

	const previewDomain = getDomainHost(previewDeployment?.domain as Domain);
	const issueParams = {
		owner: application?.owner || "",
		repository: application?.repository || "",
		issue_number: previewDeployment.pullRequestNumber,
		comment_id: Number.parseInt(previewDeployment.pullRequestCommentId),
		githubId: application?.githubId || "",
	};
	try {
		// Only update GitHub comments if GitHub is configured
		if (application?.githubId) {
			const commentExists = await issueCommentExists({
				...issueParams,
			});

packages/server/src/services/application.ts
same GitHub comment crash occurs in success handler

wrap this in a check for application?.githubId

		}
		if (application?.githubId) {
			const successComment = getIssueComment(
				application.name,
				"success",
				previewDomain,
			);
			await updateIssueComment({
				...issueParams,
				body: `### Dokploy Preview Deployment\n\n${successComment}`,
			});
		}

packages/server/src/services/application.ts
same GitHub comment crash in error handler

		const comment = getIssueComment(application.name, "error", previewDomain);
		if (application?.githubId) {
			await updateIssueComment({
				...issueParams,
				body: `### Dokploy Preview Deployment\n\n${comment}`,
			});
		}

packages/server/src/services/application.ts
same GitHub crash in rebuildPreviewApplication

all GitHub comment operations need to check if application?.githubId exists first


packages/server/src/services/application.ts
missing githubId check in success handler

		const successComment = getIssueComment(
			application.name,
			"success",
			previewDomain,
		);
		if (application?.githubId) {
			await updateIssueComment({
				...issueParams,
				body: `### Dokploy Preview Deployment\n\n${successComment}`,
			});
		}

packages/server/src/services/application.ts
missing githubId check in error handler

		const comment = getIssueComment(application.name, "error", previewDomain);
		if (application?.githubId) {
			await updateIssueComment({
				...issueParams,
				body: `### Dokploy Preview Deployment\n\n${comment}`,
			});
		}

@kopandante
Copy link
Author

Superseded by #3784

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