From b1795e1d3cf73fe28508cde6016a208be93103fd Mon Sep 17 00:00:00 2001
From: Mauricio Siu <47042324+Siumauricio@users.noreply.github.com>
Date: Sat, 8 Aug 2026 23:37:07 -0600
Subject: [PATCH] Merge pull request #5005 from
Dokploy/fix/postgres-image-mountpath-warning
fix: warn on postgres image change when the implied data directory mismatches the mounted volume
(cherry picked from commit f08c53c9b74279ab0df9ed3410981d6c708dd5f5)
[skip ci]
---
.../postgres/advanced/show-custom-command.tsx | 47 +++++++++++++++++++
1 file changed, 47 insertions(+)
diff --git a/apps/dokploy/components/dashboard/postgres/advanced/show-custom-command.tsx b/apps/dokploy/components/dashboard/postgres/advanced/show-custom-command.tsx
index 07e059ce8..4023230f8 100644
--- a/apps/dokploy/components/dashboard/postgres/advanced/show-custom-command.tsx
+++ b/apps/dokploy/components/dashboard/postgres/advanced/show-custom-command.tsx
@@ -4,6 +4,7 @@ import { useEffect } from "react";
import { useFieldArray, useForm } from "react-hook-form";
import { toast } from "sonner";
import { z } from "zod";
+import { AlertBlock } from "@/components/shared/alert-block";
import { Button } from "@/components/ui/button";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import {
@@ -18,6 +19,19 @@ import { Input } from "@/components/ui/input";
import { api } from "@/utils/api";
import type { ServiceType } from "../../application/advanced/show-resources";
+const getPostgresMountPath = (dockerImage: string): string => {
+ const versionMatch = dockerImage.match(/postgres:(\d+)/);
+ if (versionMatch?.[1]) {
+ const version = Number.parseInt(versionMatch[1], 10);
+ if (version >= 18) {
+ return `/var/lib/postgresql/${version}/docker`;
+ }
+ }
+ return "/var/lib/postgresql/data";
+};
+
+const POSTGRES_DATA_PATH_REGEX = /^\/var\/lib\/postgresql(\/|$)/;
+
const addDockerImage = z.object({
dockerImage: z.string().min(1, "Docker image is required"),
command: z.string(),
@@ -91,6 +105,27 @@ export const ShowCustomCommand = ({ id, type }: Props) => {
}
}, [data, form]);
+ const dockerImage = form.watch("dockerImage");
+
+ const mountPathWarning = (() => {
+ if (type !== "postgres" || !dockerImage) return null;
+ const mounts = data && "mounts" in data ? data.mounts : [];
+ const dataMounts = mounts.filter(
+ (mount) =>
+ mount.type === "volume" &&
+ POSTGRES_DATA_PATH_REGEX.test(mount.mountPath),
+ );
+ if (dataMounts.length === 0) return null;
+ const expectedPath = getPostgresMountPath(dockerImage);
+ if (dataMounts.some((mount) => mount.mountPath === expectedPath)) {
+ return null;
+ }
+ return {
+ expectedPath,
+ currentPath: dataMounts.map((mount) => mount.mountPath).join(", "),
+ };
+ })();
+
const onSubmit = async (formData: AddDockerImage) => {
await mutateAsync({
mongoId: id || "",
@@ -139,6 +174,18 @@ export const ShowCustomCommand = ({ id, type }: Props) => {
)}
/>
+ {mountPathWarning && (
+
+ This image expects its data directory under{" "}
+ {mountPathWarning.expectedPath}, but the
+ volume of this database is mounted at{" "}
+ {mountPathWarning.currentPath}. Changing the
+ image does not migrate existing data — Postgres may
+ crash-loop or start with an empty database. Adjust the
+ volume mount path in the Volumes section or keep a
+ compatible image before saving.
+
+ )}