diff --git a/content/docs/get-started/internal-postgresql-upgrade.mdx b/content/docs/get-started/internal-postgresql-upgrade.mdx
new file mode 100644
index 00000000..e1efce93
--- /dev/null
+++ b/content/docs/get-started/internal-postgresql-upgrade.mdx
@@ -0,0 +1,128 @@
+---
+title: Upgrading (internal Postgresql)
+description: Upgrade or roll back the PostgreSQL database used by your self-hosted Coolify instance.
+---
+
+# Internal PostgreSQL upgrade
+
+Coolify self-hosted instances use an internal PostgreSQL database container named `coolify-db`.
+Normal Coolify updates do **not** automatically upgrade PostgreSQL to a new major version.
+
+PostgreSQL major upgrades, for example `15` to `18`, require a data migration. Changing only the Docker image is not enough, because PostgreSQL will reject data directories created by a different major version.
+
+
+
+Create or verify a recent Coolify backup before upgrading the internal PostgreSQL database.
+The upgrade script keeps the previous Docker volume for rollback, but you should still have an external backup before changing database versions.
+
+
+
+## When to use this
+
+Use this only when you need to upgrade the **internal Coolify database** to a newer PostgreSQL major version.
+
+Do not use this for PostgreSQL databases that you created as project resources in Coolify. Those databases have their own lifecycle and backup/restore process.
+
+## Upgrade PostgreSQL
+
+Run the script on your Coolify server:
+
+```bash
+/data/coolify/source/upgrade-postgres.sh 18
+```
+
+Replace `18` with the target PostgreSQL major version.
+
+The script will:
+
+1. Detect the current `coolify-db` PostgreSQL version.
+2. Stop the `coolify` application container to prevent writes.
+3. Create a compressed `pg_dumpall` backup in `/data/coolify/backups/internal-postgres/`.
+4. Create a new Docker volume, for example `coolify-db-pg18`.
+5. Restore the dump into a temporary PostgreSQL container using the target version.
+6. Smoke-test the restored database.
+7. Write `/data/coolify/source/docker-compose.postgres-upgrade.yml`.
+8. Restart the Coolify stack using the new PostgreSQL image and volume.
+9. Save rollback metadata in `/data/coolify/source/postgres-upgrade-rollback.env`.
+
+
+
+PostgreSQL 18 and newer use `/var/lib/postgresql` as the container mount path.
+Older versions use `/var/lib/postgresql/data`.
+The script chooses the correct path automatically.
+
+
+
+## What changes in Docker Compose
+
+The script does not modify `docker-compose.yml` or `docker-compose.prod.yml`.
+Instead, it creates this override file:
+
+```text
+/data/coolify/source/docker-compose.postgres-upgrade.yml
+```
+
+For PostgreSQL 18, it looks similar to this:
+
+```yaml
+services:
+ postgres:
+ image: "postgres:18-alpine"
+ volumes:
+ - coolify-db:/var/lib/postgresql
+volumes:
+ coolify-db:
+ name: "coolify-db-pg18"
+ external: true
+```
+
+Future Coolify updates include this override file automatically, so the upgraded image and volume stay active after normal upgrades.
+
+If you also have `/data/coolify/source/docker-compose.custom.yml`, the PostgreSQL upgrade override is loaded after the custom compose file. For conflicting `postgres` service settings, the PostgreSQL upgrade override takes precedence.
+
+## Roll back
+
+If the upgraded database does not work, run:
+
+```bash
+/data/coolify/source/upgrade-postgres.sh rollback
+```
+
+Rollback uses the metadata saved during the last successful upgrade.
+It restores the previously active PostgreSQL image, Docker volume, and mount path.
+
+For example:
+
+```text
+15 → 18 → rollback = 15
+15 → 18 → 19 → rollback = 18
+```
+
+Rollback is one-step only. Each successful upgrade replaces the rollback metadata with the previously active version.
+
+The upgraded Docker volume is not deleted during rollback. You can inspect or remove it manually after you confirm the rollback works.
+
+## Files created by the script
+
+| File | Purpose |
+| --- | --- |
+| `/data/coolify/source/docker-compose.postgres-upgrade.yml` | Compose override that points Coolify to the upgraded PostgreSQL image and Docker volume. |
+| `/data/coolify/source/postgres-upgrade-rollback.env` | Metadata used by `upgrade-postgres.sh rollback`. |
+| `/data/coolify/source/postgres-upgrade-*.log` | Upgrade or rollback logs. |
+| `/data/coolify/backups/internal-postgres/postgres-upgrade-*.sql.gz` | Compressed database dump created before migration. |
+
+## Verify the active compose configuration
+
+To inspect the final Compose configuration that will be used by Coolify, run:
+
+```bash
+docker compose \
+ --env-file /data/coolify/source/.env \
+ -f /data/coolify/source/docker-compose.yml \
+ -f /data/coolify/source/docker-compose.prod.yml \
+ -f /data/coolify/source/docker-compose.custom.yml \
+ -f /data/coolify/source/docker-compose.postgres-upgrade.yml \
+ config
+```
+
+If you do not have `docker-compose.custom.yml`, remove that line from the command.
diff --git a/content/docs/get-started/meta.json b/content/docs/get-started/meta.json
index 8fa5a842..533f089a 100644
--- a/content/docs/get-started/meta.json
+++ b/content/docs/get-started/meta.json
@@ -5,6 +5,7 @@
"introduction",
"installation",
"upgrade",
+ "internal-postgresql-upgrade",
"downgrade",
"uninstallation",
"cloud",
@@ -19,4 +20,4 @@
"sponsors",
"contribute"
]
-}
\ No newline at end of file
+}
diff --git a/content/docs/knowledge-base/custom-compose-overrides.mdx b/content/docs/knowledge-base/custom-compose-overrides.mdx
index 3f5b3358..42564edb 100644
--- a/content/docs/knowledge-base/custom-compose-overrides.mdx
+++ b/content/docs/knowledge-base/custom-compose-overrides.mdx
@@ -29,6 +29,25 @@ docker compose \
Docker Compose [merges these files](https://docs.docker.com/compose/how-tos/multiple-compose-files/merge/?utm_source=coolify.io) in order — properties in later files override the same properties in earlier files. You only need to specify the keys you want to change.
+If you use the [internal PostgreSQL upgrade script](/get-started/internal-postgresql-upgrade), Coolify also creates:
+
+```text
+/data/coolify/source/docker-compose.postgres-upgrade.yml
+```
+
+When that file exists, it is loaded **after** `docker-compose.custom.yml`:
+
+```bash
+docker compose \
+ -f docker-compose.yml \
+ -f docker-compose.prod.yml \
+ -f docker-compose.custom.yml \
+ -f docker-compose.postgres-upgrade.yml \
+ up -d
+```
+
+This lets the PostgreSQL upgrade override keep the upgraded PostgreSQL image and Docker volume active across future Coolify upgrades. If both files define conflicting `postgres` service settings, `docker-compose.postgres-upgrade.yml` takes precedence because it is loaded last.
+
@@ -151,6 +170,18 @@ docker compose \
config
```
+If `/data/coolify/source/docker-compose.postgres-upgrade.yml` exists, include it too so you validate the same file order Coolify will use:
+
+```bash
+cd /data/coolify/source
+docker compose \
+ -f docker-compose.yml \
+ -f docker-compose.prod.yml \
+ -f docker-compose.custom.yml \
+ -f docker-compose.postgres-upgrade.yml \
+ config
+```
+
If the output is valid merged YAML with no errors, your file is safe to use.
diff --git a/scripts/generate-fumadocs-content.mjs b/scripts/generate-fumadocs-content.mjs
index d27e5964..128b1c6c 100644
--- a/scripts/generate-fumadocs-content.mjs
+++ b/scripts/generate-fumadocs-content.mjs
@@ -41,6 +41,7 @@ const sidebarMetas = {
'introduction',
'installation',
'upgrade',
+ 'internal-postgresql-upgrade',
'downgrade',
'uninstallation',
'cloud',