New to KubeDB? Please start here.

Neo4j StorageClass Migration

This guide shows how to migrate the StorageClass of a KubeDB-managed Neo4j cluster using Neo4jOpsRequest with type: StorageMigration.

Before You Begin

  • You need a Kubernetes cluster and kubectl configured.
  • Install KubeDB operator following setup guide.
  • Ensure at least two StorageClass resources are available in your cluster.

Use a dedicated namespace for this walkthrough:

$ kubectl create ns demo
namespace/demo created

Prepare Neo4j Database

First, verify available storage classes:

$ kubectl get sc
NAME                   PROVISIONER             RECLAIMPOLICY   VOLUMEBINDINGMODE      ALLOWVOLUMEEXPANSION   AGE
custom-longhorn        driver.longhorn.io      Delete          WaitForFirstConsumer   true                   3h38m
local-path (default)   rancher.io/local-path   Delete          WaitForFirstConsumer   false                  4h26m
longhorn (default)     driver.longhorn.io      Delete          Immediate              true                   3h43m
longhorn-static        driver.longhorn.io      Delete          Immediate              true                   3h43m

We will deploy Neo4j with local-path, then migrate to custom-longhorn.

Both old and new PVCs should stay on the same node. If the old class uses WaitForFirstConsumer, use a new class with WaitForFirstConsumer as well.

Apply the Neo4j database manifest:

$ cat <<'EOF' | kubectl apply -f -
apiVersion: kubedb.com/v1alpha2
kind: Neo4j
metadata:
  name: neo4j-test
  namespace: demo
spec:
  replicas: 3
  deletionPolicy: WipeOut
  version: "2025.12.1"
  storage:
    storageClassName: "local-path"
    accessModes:
      - ReadWriteOnce
    resources:
      requests:
        storage: 2Gi
EOF
neo4j.kubedb.com/neo4j-test created

$ kubectl get neo4j,pvc -n demo
NAME                      VERSION     STATUS   AGE
neo4j.kubedb.com/neo4j-test   2025.12.1   Ready    2m

NAME                               STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS   AGE
persistentvolumeclaim/data-neo4j-test-0   Bound    ...      2Gi        RWO            local-path     2m
persistentvolumeclaim/data-neo4j-test-1   Bound    ...      2Gi        RWO            local-path     2m
persistentvolumeclaim/data-neo4j-test-2   Bound    ...      2Gi        RWO            local-path     2m

Apply StorageMigration OpsRequest

To migrate StorageClass, create a Neo4jOpsRequest:

$ cat <<'EOF' | kubectl apply -f -
apiVersion: ops.kubedb.com/v1alpha1
kind: Neo4jOpsRequest
metadata:
  name: storage-migration
  namespace: demo
spec:
  type: StorageMigration
  databaseRef:
    name: neo4j-test
  migration:
    storageClassName: custom-longhorn
    oldPVReclaimPolicy: Delete
  timeout: 3000s
EOF
neo4jopsrequest.ops.kubedb.com/storage-migration created

Here,

  • spec.type must be StorageMigration.
  • spec.databaseRef.name points to target Neo4j database.
  • spec.migration.storageClassName is the destination StorageClass.
  • spec.migration.oldPVReclaimPolicy controls old PV reclaim policy.

To retain old PVs after migration, use oldPVReclaimPolicy: Retain.

Verify StorageClass Migration

Watch the OpsRequest status:

$ kubectl get neo4jopsrequest -n demo -w
NAME                TYPE               STATUS       AGE
storage-migration   StorageMigration   Successful   8m

Check PVC storage class after migration:

$ kubectl get pvc -n demo
NAME                STATUS   VOLUME   CAPACITY   ACCESS MODES   STORAGECLASS      AGE
data-neo4j-test-0   Bound    ...      2Gi        RWO            custom-longhorn   14m
data-neo4j-test-1   Bound    ...      2Gi        RWO            custom-longhorn   14m
data-neo4j-test-2   Bound    ...      2Gi        RWO            custom-longhorn   14m

The PVCs now use custom-longhorn, which confirms successful StorageClass migration.

Cleanup

$ kubectl delete neo4jopsrequest -n demo storage-migration
$ kubectl delete neo4j -n demo neo4j-test
$ kubectl delete ns demo