Migrate DB from pgvecto.rs to VectorChord
Since chart version 25 the PostgreSQL extension is changed from pgvecto.rs to VectorChord. Therefore before upgrading to chart version 25, you need to migrate your database.
Prerequisite
Section titled “Prerequisite”- This guide is made and tested with Immich chart 24.13.2. Make sure you are on chart version 24.x.x .
- In this guide we are using the shell of the CNPG pods. How to exec in a pod, is something we assume you’re familiar with.
- Also you need to be familiar with running ‘kubectl’ commands.
- We assume Immich is in the namespace
Immich, when different adapt accordingly.
Change database user rights
Section titled “Change database user rights”Typically Immich expects superuser permission in the database. This is needed for this upgrade, but also practical for future. With this permission automated database dumps can also be used inside Immich itself. Also with a new version of VectorChord reindex the database will be automaticly.
- Exec into pod
immich-cnpg-main-1 - run:
psql immich - run:
ALTER USER immich WITH SUPERUSER;
When all went OK it looks like this:
postgres@immich-cnpg-main-1:/$ psql immichpsql (16.3 (Debian 16.3-1.pgdg110+1))Type "help" for help.
immich=# ALTER USER immich WITH SUPERUSER;ALTER ROLEimmich=#Only running CNPG pods are allowed
Section titled “Only running CNPG pods are allowed”- Scale all deployments down to “0”
- Add to your .Values
workload: main: replicas: 0- Check if immich deployment is 0/0 with
kubectl get deployments -n immich - run:
kubectl scale --replicas=0 deployment/immich-machinelearning -n immich - run:
kubectl scale --replicas=0 deployment/immich-microservices -n immich
- Check if all deployments are now scaled down and only cnpg and redis pods are their.
- run:
kubectl get deployments,pods -n immich
kubectl get deployments,pods -n immichNAME READY UP-TO-DATE AVAILABLE AGEdeployment.apps/immich 0/0 0 0 34mdeployment.apps/immich-machinelearning 0/0 0 0 34mdeployment.apps/immich-microservices 0/0 0 0 34m
NAME READY STATUS RESTARTS AGEpod/immich-cnpg-main-1 1/1 Running 0 28mpod/immich-cnpg-main-2 1/1 Running 0 27mpod/immich-redis-0 1/1 Running 0 3m39sMigration Step 1, while pgvecto.rs is installed.
Section titled “Migration Step 1, while pgvecto.rs is installed.”- Exec into pod “immich-cnpg-main-1”
- run:
psql immich - run:
SELECT atttypmod as dimsize FROM pg_attribute f JOIN pg_class c ON c.oid = f.attrelid WHERE c.relkind = 'r'::char AND f.attnum > 0 AND c.relname = 'smart_search'::text AND f.attname = 'embedding'::text;-
Write down the dimsize NUMBER, given as output
-
run:
DROP INDEX IF EXISTS clip_index;DROP INDEX IF EXISTS face_index;ALTER TABLE smart_search ALTER COLUMN embedding SET DATA TYPE real[];ALTER TABLE face_search ALTER COLUMN embedding SET DATA TYPE real[];When all went OK it looks like this (NUMBER can be different):
postgres@immich-cnpg-main-1:/$ psql immichpsql (16.3 (Debian 16.3-1.pgdg110+1))Type "help" for help.
immich=# SELECT atttypmod as dimsize FROM pg_attribute f JOIN pg_class c ON c.oid = f.attrelid WHERE c.relkind = 'r'::char AND f.attnum > 0 AND c.relname = 'smart_search'::text AND f.attname = 'embedding'::text; dimsize--------- 512(1 row)
immich=# DROP INDEX IF EXISTS clip_index;DROP INDEX IF EXISTS face_index;ALTER TABLE smart_search ALTER COLUMN embedding SET DATA TYPE real[];ALTER TABLE face_search ALTER COLUMN embedding SET DATA TYPE real[];DROP INDEXDROP INDEXALTER TABLEALTER TABLEimmich=#Migration Step 2, change deployment to VectorChord
Section titled “Migration Step 2, change deployment to VectorChord”- Add to your .Values
cnpg: main: type: vectorchordCheck:
- run:
kubectl get deployments,pods -n immich
After deployment, most likely immich-cnpg-main-2 is upgraded and immich-cnpg-main-1 in a CrashLoopBackOff state, when that is the case:
- run:
kubectl delete pod immich-cnpg-main-1 -n immich
Make sure the machinelearning and microservices will be scaled down again:
- run:
kubectl scale --replicas=0 deployment/immich-machinelearning -n immich - run:
kubectl scale --replicas=0 deployment/immich-microservices -n immich
Check if all is in the desired state:
- run:
kubectl get deployments,pods -n immich
kubectl get deployments,pods -n immichNAME READY UP-TO-DATE AVAILABLE AGEdeployment.apps/immich 0/0 0 0 58mdeployment.apps/immich-machinelearning 0/0 0 0 58mdeployment.apps/immich-microservices 0/0 0 0 58m
NAME READY STATUS RESTARTS AGEpod/immich-cnpg-main-1 1/1 Running 0 2m57spod/immich-cnpg-main-2 1/1 Running 0 7m26spod/immich-redis-0 1/1 Running 0 7m27sCheck if image vectorchord is used:
- run:
kubectl get pods -n immich -o yaml| grep "image:"
kubectl get pods -n immich -o yaml| grep "image:" image: ghcr.io/tensorchord/cloudnative-vectorchord:16.10-0.5.3 image: ghcr.io/cloudnative-pg/cloudnative-pg:1.27.1 image: ghcr.io/tensorchord/cloudnative-vectorchord:16.10-0.5.3 image: ghcr.io/cloudnative-pg/cloudnative-pg:1.27.1 image: ghcr.io/tensorchord/cloudnative-vectorchord:16.10-0.5.3 image: ghcr.io/cloudnative-pg/cloudnative-pg:1.27.1 image: ghcr.io/tensorchord/cloudnative-vectorchord:16.10-0.5.3 image: ghcr.io/cloudnative-pg/cloudnative-pg:1.27.1 image: docker.io/bitnamisecure/redis:latest@sha256:142ab4d0c251bcf5466fffd33766350af718a6725cb926710be19fad00b2b035 image: sha256:63a40000acab0440264e4176e2345571beb8f1097e0355f8d216768bdf4be7f0Migration Step 3, while VectorChord is installed.
Section titled “Migration Step 3, while VectorChord is installed.”- Exec into pod “immich-cnpg-main-2” (most lickely main-1 is now a read-only, so therefore we use main-2)
- run:
psql immich - run, with Replacing
with the number from step 1 :
CREATE EXTENSION IF NOT EXISTS vchord CASCADE;ALTER TABLE smart_search ALTER COLUMN embedding SET DATA TYPE vector(<number>);ALTER TABLE face_search ALTER COLUMN embedding SET DATA TYPE vector(512);When all is OK it looks like this:
postgres@immich-cnpg-main-2:/$ psql immichpsql (16.10 (Debian 16.10-1.pgdg12+1))Type "help" for help.
immich=# CREATE EXTENSION IF NOT EXISTS vchord CASCADE;ALTER TABLE smart_search ALTER COLUMN embedding SET DATA TYPE vector(512);ALTER TABLE face_search ALTER COLUMN embedding SET DATA TYPE vector(512);NOTICE: installing required extension "vector"CREATE EXTENSIONALTER TABLEALTER TABLEimmich=#If you get this as output:
ERROR: cannot execute CREATE EXTENSION in a read-only transactionERROR: cannot execute ALTER TABLE in a read-only transactionERROR: cannot execute ALTER TABLE in a read-only transactionExec into the other CNPG pod and try again.
Testing
Section titled “Testing”- Remove:
workload: main: replicas: 0-
Now let it all deploy, all pods will be go up include machinelearning and microservices
-
Check the logs: Immich will now create new indices using VectorChord, will looks like this:
Postgres notice: { severity_local: 'INFO', severity: 'INFO', code: '00000', message: 'maintain: number_of_formerly_allocated_pages = 0', file: 'algo.rs', line: '100', routine: 'vchord::index::vchordrq::algo::maintain'}- When the logs indicate:
[Nest] 22 - 10/23/2025, 9:09:26 PM LOG [Api:NestApplication] Nest application successfully started[Nest] 22 - 10/23/2025, 9:09:26 PM LOG [Api:Bootstrap] Immich Server is listening on http://[::1]:10323 [v2.1.0] [production][Nest] 22 - 10/23/2025, 9:10:26 PM LOG [Api:MachineLearningRepository] Machine learning server became healthy (http://immich-machinelearning:10003).- All went OK
Change chart version
Section titled “Change chart version”- Change your
chart versionto25.0.0 - Remove:
cnpg: main: type: vectorchord- You are ready to use Immich again! Have fun!
References
Section titled “References”The origin material for this guide is available on the Immich site -> Migration steps (manual).
Support
Section titled “Support”If you have any issues with following this guide, we can be reached using Discord for real-time feedback and support.