🆕 New to KubeDB? Start with the quickstart guide before continuing here.
Neo4j Vertical Scaling with KubeDB
Vertical scaling adjusts the CPU and memory requests and limits on running Neo4j pods without recreating the database or losing data. KubeDB handles the rollout automatically through Neo4jOpsRequest.
This guide walks you through:
- Deploying a Neo4j cluster
- Checking current pod resource allocation
- Applying a vertical scale-up
- Verifying the new resources are live
How It Works
KubeDB uses Neo4jOpsRequest with type: VerticalScaling to update pod resources. Under the hood it:
- Patches the StatefulSet container spec with the new CPU/memory values
- Performs a rolling restart of Neo4j pods one at a time
- Marks the operation
Successfulonce all pods are running with the new resources
Prerequisites
| Requirement | Details |
|---|---|
| KubeDB installed | Provisioner and Ops-manager operators running |
kubectl configured | With permissions to create namespaces and resources |
See also: Neo4j · Neo4jOpsRequest · Vertical Scaling Overview
Step 1 — Set Up the Namespace
$ kubectl create ns demo
Step 2 — Deploy Neo4j
Save this as neo4j.yaml:
apiVersion: kubedb.com/v1alpha2
kind: Neo4j
metadata:
name: neo4j-test
namespace: demo
spec:
version: "2025.12.1"
replicas: 3
storage:
resources:
requests:
storage: 2Gi
storageClassName: standard
accessModes:
- ReadWriteOnce
podTemplate:
spec:
resources:
requests:
cpu: "250m"
memory: "1Gi"
limits:
cpu: "500m"
memory: "1Gi"
deletionPolicy: WipeOut
Apply it and wait for the cluster to become ready:
$ kubectl apply -f neo4j.yaml
$ kubectl get neo4j -n demo neo4j-test -w
Wait until STATUS shows Ready before proceeding.
NAME VERSION STATUS AGE
neo4j-test 2025.12.1 Ready 3m
Step 3 — Check Current Pod Resources
Before scaling, record the existing CPU and memory values so you can confirm the change later.
$ kubectl get pod -n demo neo4j-test-0 \
-o jsonpath='{.spec.containers[0].resources}' | jq .
Expected output:
{
"limits": { "cpu": "500m", "memory": "1Gi" },
"requests": { "cpu": "250m", "memory": "1Gi" }
}
Step 4 — Apply the Vertical Scaling OpsRequest
The Neo4jOpsRequest below raises the CPU limit to 1500m and memory to 4Gi.
Save this as neo4j-vertical-scale.yaml:
apiVersion: ops.kubedb.com/v1alpha1
kind: Neo4jOpsRequest
metadata:
name: neo4j-vertical-scale
namespace: demo
spec:
type: VerticalScaling
databaseRef:
name: neo4j-test
verticalScaling:
server:
resources:
requests:
cpu: "700m"
memory: "4Gi"
limits:
cpu: "1500m"
memory: "4Gi"
Apply it and wait for completion:
$ kubectl apply -f neo4j-vertical-scale.yaml
$ kubectl wait --for=jsonpath='{.status.phase}'=Successful \
neo4jopsrequest/neo4j-vertical-scale \
-n demo --timeout=600s
Expected output:
neo4jopsrequest.ops.kubedb.com/neo4j-vertical-scale condition met
What Happens During This Step
Once you apply the OpsRequest, KubeDB Ops-manager picks it up and begins the scaling process:
- The OpsRequest moves to
Progressingphase - KubeDB patches the StatefulSet with the new resource values
- Pods are restarted one at a time — each must reach
Runningbefore the next restarts - Once all pods are up with the new resources, the OpsRequest moves to
Successful
You can watch the live status with:
$ kubectl get neo4jopsrequest -n demo neo4j-vertical-scale -w
Step 5 — Verify the New Resources
$ kubectl get neo4jopsrequest -n demo neo4j-vertical-scale
$ kubectl get pod -n demo neo4j-test-0 \
-o jsonpath='{.spec.containers[0].resources}' | jq .
Expected output:
NAME TYPE STATUS AGE
neo4j-vertical-scale VerticalScaling Successful 101s
{
"limits": { "cpu": "1500m", "memory": "4Gi" },
"requests": { "cpu": "700m", "memory": "4Gi" }
}
✅ The values now match
spec.verticalScaling.server.resources— the scaling is complete.
Understanding the OpsRequest Fields
| Field | Description |
|---|---|
spec.type | VerticalScaling — identifies this as a resource update operation |
spec.databaseRef.name | Name of the target Neo4j resource |
spec.verticalScaling.server.resources.requests | Minimum CPU/memory guaranteed to the pod |
spec.verticalScaling.server.resources.limits | Maximum CPU/memory the pod is allowed to use |
Tip: Always set
requestsequal tolimitsfor Neo4j in production. This gives the pod a Guaranteed QoS class, preventing it from being evicted under memory pressure.
Troubleshooting
If this OpsRequest does not finish, first inspect the affected pod and then check the kubedb-ops-manager operator logs for the exact error. For a shared checklist, see the Neo4j Ops Request Overview.
OpsRequest stays in Progressing and never completes
Check the pod that is being restarted and look for scheduling or resource issues:
$ kubectl get pods -n demo -l app.kubernetes.io/instance=neo4j-test
$ kubectl describe pod -n demo neo4j-test-0
$ kubectl describe node <node-name> | grep -A 10 "Allocated resources"
OpsRequest moves to Failed
Read the failure condition and then inspect the kubedb-ops-manager logs:
kubectl get neo4jopsrequest -n demo neo4j-vertical-scale -o jsonpath='{.status.conditions}' | jq .
kubectl logs -n <kubedb-namespace> -l app.kubernetes.io/name=kubedb-ops-manager --tail=50
Pod restarts repeatedly after scaling (CrashLoopBackOff)
If Neo4j does not start with the new memory values, inspect the previous pod logs:
kubectl logs -n demo neo4j-test-0 --previous
jq not installed
Use jsonpath directly:
kubectl get neo4jopsrequest -n demo neo4j-vertical-scale -o jsonpath='{.status.conditions}'
Cleanup
kubectl delete neo4jopsrequest -n demo neo4j-vertical-scale
kubectl delete neo4j -n demo neo4j-test
kubectl delete ns demo
Next Steps
- Neo4j Horizontal Scaling — add or remove cluster members
- Neo4j Version Upgrade — roll to a newer Neo4j release
- Neo4j Volume Expansion — increase persistent storage































