Neo4jEnterpriseStandalone API Reference¶
The Neo4jEnterpriseStandalone custom resource manages single-node Neo4j Enterprise deployments for development, testing, and simple production workloads that don't require clustering capabilities.
Overview¶
- API Version:
neo4j.neo4j.com/v1beta1 - Kind:
Neo4jEnterpriseStandalone - Supported Neo4j Versions: 5.26.x (last semver LTS) and 2025.01.0+ (CalVer)
- Architecture: Single StatefulSet with unified clustering infrastructure
- Database Support: Compatible with Neo4jDatabase CRD for automated database creation
- Plugin Support: Full compatibility with Neo4jPlugin CRD
- Name Limit:
metadata.nameis at most 63 characters (validated)
Architecture¶
Unified Infrastructure: Neo4jEnterpriseStandalone uses the same clustering infrastructure as cluster deployments but with a single server:
- Single StatefulSet:
{standalone-name}with 1 replica - Single Pod: Named
{standalone-name}-0 - Health Probes: Readiness, liveness, and startup probes using
/conf/health.sh(checks Neo4j process and HTTP port) - ConfigMap:
{standalone-name}-configcontainingneo4j.confandhealth.sh - Database Compatibility: Supports Neo4jDatabase resources for automated database creation
- Plugin Compatibility: Full support for Neo4jPlugin installation and management
- Backup Integration: Compatible with Neo4jBackup/Restore for data protection
Related Resources¶
Neo4jDatabase- Create databases within the standalone instanceNeo4jPlugin- Install plugins (APOC, GDS, etc.)Neo4jBackup- Schedule automated backupsNeo4jRestore- Restore from backupsNeo4jEnterpriseCluster- For clustered deployments
When to Use Neo4jEnterpriseStandalone¶
Use Neo4jEnterpriseStandalone when you need:
- Development environments with a single Neo4j instance
- Testing scenarios that don't require clustering
- Simple production workloads with basic availability requirements
- Migration from Community Edition to Enterprise features without clustering
- Cost-effective deployments that don't need high availability
Note: For production workloads requiring high availability, use
Neo4jEnterpriseClusterinstead.
Spec Fields¶
Required Fields¶
image (ImageSpec)¶
Specifies the Neo4j Docker image to use.
| Field | Type | Description |
|---|---|---|
repo |
string |
Required. Docker repository (no schema default; typically "neo4j") |
tag |
string |
Required. Neo4j version tag — 5.26 LTS or any CalVer release (2025.x, 2026.x, and onward) |
pullPolicy |
string |
Image pull policy: "Always", "IfNotPresent" (default), "Never" |
pullSecrets |
[]string |
Image pull secrets for private registries |
image:
repo: neo4j # Docker repository
tag: "5.26-enterprise" # Neo4j version: 5.26 LTS or any CalVer release (2025.x, 2026.x, ...)
pullPolicy: IfNotPresent # Image pull policy
pullSecrets: [] # Image pull secrets
acceptLicenseAgreement (string)¶
Your explicit acceptance of the Neo4j Enterprise license. Required — the operator refuses to deploy until it is set.
| Value | Meaning |
|---|---|
yes |
Accept the Neo4j Enterprise commercial license agreement |
eval |
Accept the 30-day evaluation license |
This operator is independent and does not provide or accept a Neo4j license on your behalf — you must hold your own valid Neo4j Enterprise license.
storage (StorageSpec)¶
Defines storage configuration for the Neo4j data volume.
| Field | Type | Description |
|---|---|---|
className |
string |
Storage class for the data PVC. Optional — if omitted, the PVC inherits the cluster's default StorageClass. When set, the named class must exist: the operator reports an explicit error (a StorageClassNotFound event and Failed status) rather than leaving the pod Pending. Immutable after creation. |
size |
string |
Required. Storage size (e.g., "10Gi"). Must be a valid Kubernetes quantity greater than zero ("1.5Gi" is fine; "fifty" or "10 Gi" is refused by validation). Can be increased after creation — the operator automatically expands the PVC and recreates the StatefulSet with zero downtime. Cannot be decreased. Requires allowVolumeExpansion: true on the StorageClass. |
retentionPolicy |
string |
PVC retention policy: "Delete" (default) permanently removes PVCs on deletion; "Retain" preserves them. Use Retain for production to prevent data loss. See Storage and PVC Retention. |
storage:
className: standard # Storage class name
size: "10Gi" # Storage size
retentionPolicy: Delete # PVC retention policy (Delete/Retain)
Optional Fields¶
resources (ResourceRequirements)¶
Resource limits and requests for the Neo4j pod.
env ([]EnvVar)¶
Environment variables for the Neo4j container.
env:
- name: NEO4J_dbms_jvm_additional
value: "-XX:+UseG1GC"
# Note: NEO4J_ACCEPT_LICENSE_AGREEMENT and NEO4J_AUTH are operator-managed and
# ignored here — set spec.acceptLicenseAgreement and spec.auth instead.
# Use the Neo4jPlugin CRD for plugin management instead of NEO4J_PLUGINS.
config (map[string]string)¶
Custom Neo4j configuration. The operator uses unified clustering infrastructure for standalone deployments (Neo4j 5.26+ approach).
config:
server.memory.heap.initial_size: "1G"
server.memory.heap.max_size: "2G"
server.memory.pagecache.size: "1G"
dbms.security.procedures.unrestricted: "gds.*,apoc.*"
db.logs.query.enabled: "INFO" # enum: OFF | INFO | VERBOSE (not a boolean)
db.logs.query.threshold: "1s"
# Neo4j 5.26+ configuration syntax
server.default_listen_address: "0.0.0.0"
server.discovery.advertised_address: "$(hostname -f)"
Automatically Managed: The following configurations are managed by the operator and must not be set in spec.config:
dbms.cluster.discovery.*- Discovery settings (LIST resolver with pod FQDNs, injected by startup script)dbms.cluster.endpoints- CalVer endpoint list (injected by startup script)server.bolt.listen_address- Network listenersserver.http.listen_address- HTTP endpointsNEO4J_AUTH- Authentication setup (when using adminSecret)
Critical for Standalone: The operator automatically configures clustering infrastructure but ensures single-node operation.
tls (TLSSpec)¶
TLS/SSL configuration for secure connections. Same shape as
Neo4jEnterpriseCluster.spec.tls.
tls:
mode: cert-manager # cert-manager or disabled (only valid values)
issuerRef: # REQUIRED when mode=cert-manager
name: ca-cluster-issuer
kind: ClusterIssuer
Note on
strictPeerValidation: the field is present on the sharedTLSSpecbut has no effect onNeo4jEnterpriseStandalone— single-server deployments have no intra-cluster traffic, so there's no cluster SSL policy to govern. Setting it tofalseon a standalone raises aValidationWarningevent saying so (trueis the CRD default, so it is not warned about); the standalone is still accepted.Note on
certificateSecret: the field is present on the sharedTLSSpecbut is never read: the operator always uses the cert-manager Secret{name}-tls-secret. AValidationWarningevent is raised whenever it is set, whatevermodeis.
auth (AuthSpec)¶
Authentication configuration.
service (ServiceSpec)¶
Service configuration for external access.
service:
type: ClusterIP # ClusterIP, NodePort, LoadBalancer
annotations: # Service annotations (e.g., for cloud LB)
service.beta.kubernetes.io/aws-load-balancer-type: nlb
loadBalancerIP: "10.0.0.100" # Static IP for LoadBalancer
loadBalancerSourceRanges: # IP ranges allowed to access
- "10.0.0.0/8"
- "192.168.0.0/16"
externalTrafficPolicy: Local # Cluster or Local
dnsName: neo4j.example.com # Public DNS hostname — surfaces as the
# external-dns hostname annotation on the
# Service + Ingress, and is added to the
# cert-manager Certificate SANs when
# spec.tls is enabled. See External Access
# guide for prerequisites.
ingress: # Ingress configuration
enabled: true
className: nginx
host: neo4j.example.com
tlsSecretName: neo4j-tls
route: # OpenShift Route exposure (OpenShift only)
enabled: true
host: neo4j.apps.example.com
targetPort: 7474 # defaults to HTTP port 7474
tls:
termination: edge # edge, reencrypt, or passthrough
service.type defaults to ClusterIP. The route block is OpenShift-only.
mcp (MCPServerSpec)¶
Optional MCP server deployment using the official mcp/neo4j image (github.com/neo4j/mcp). Requires the APOC plugin for the get-schema tool.
HTTP transport (default): no static credentials in the pod; clients send Basic Auth or Bearer tokens per request.
STDIO transport: operator injects credentials from the admin secret (or spec.mcp.auth override). No Service is created.
For client configuration, see the MCP Client Setup Guide.
mcp:
enabled: true
# image defaults to mcp/neo4j:latest — no need to specify
transport: http
readOnly: true
http:
service:
type: ClusterIP
For full MCP field definitions (HTTP, TLS, service exposure, and STDIO auth), see the MCPServerSpec section.
auraFleetManagement (AuraFleetManagementSpec)¶
Enables integration with Neo4j Aura Fleet Management. The operator installs the pre-bundled fleet-management plugin and registers the Aura token automatically once the deployment is Ready.
auraFleetManagement:
enabled: true
tokenSecretRef:
name: aura-fleet-token # Secret with key "token" holding the Aura registration token
key: token # optional; defaults to "token"
For full setup instructions see Aura Fleet Management Guide.
For the full type definition — including the optional provision block, by which the operator registers the deployment and mints the token itself — see AuraFleetManagementSpec. The status.auraFleetManagement fields are the same as on the cluster.
upgradeStrategy (UpgradeStrategySpec)¶
Configures how the operator handles Neo4j version upgrades for standalone deployments. When an image tag change is detected, the operator runs a pre-upgrade health check (if enabled) before allowing the StatefulSet to update.
upgradeStrategy:
strategy: RollingUpgrade # RollingUpgrade (default) or Recreate
preUpgradeHealthCheck: true # Verify Neo4j health before upgrading
autoPauseOnFailure: true # Block upgrade if health check fails
For the full type definition see UpgradeStrategySpec.
Plugin management¶
There is no spec.plugins field on Neo4jEnterpriseStandalone. Use
separate Neo4jPlugin resources for all plugin management:
# Plugins are installed with the Neo4jPlugin CRD
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jPlugin
metadata:
name: my-apoc-plugin
spec:
clusterRef: my-standalone # References the Neo4jEnterpriseStandalone
name: apoc
version: "5.26.0"
config:
"apoc.export.file.enabled": "true"
"apoc.import.file.enabled": "true"
Plugin Installation: The Neo4jPlugin controller automatically:
- Updates the standalone StatefulSet with
NEO4J_PLUGINSenvironment variable - Adds plugin-specific configuration as
NEO4J_*environment variables - Triggers a rolling restart to apply plugin changes
- Verifies plugin installation and marks status as Ready
See the Neo4jPlugin API reference for complete documentation.
monitoring (MonitoringSpec)¶
Query performance monitoring.
monitoring:
enabled: true
slowQueryThreshold: "5s"
queryLogLevel: "INFO"
obfuscateLiterals: false
logs:
stdout: [query, security] # Neo4j's logs on standard output as JSON
logs.stdout lists the logs (query, security, debug) to also write to the container's standard output, one JSON object per line, for a node-level log collector. Turning it on or off restarts the pod once; changing the list afterwards restarts nothing. Same field as Neo4jEnterpriseCluster's; see OpenTelemetry.
audit (AuditSpec)¶
Compliance-oriented logging — security.log + query.log tuning for
PCI / HIPAA / GDPR. Same shape as
Neo4jEnterpriseCluster.spec.audit.
networkPolicy (NetworkPolicySpec)¶
Optional NetworkPolicy emission that restricts ingress to the Neo4j backup port (6362) to operator-managed backup pods only. Public client ports remain open. Disabled by default. Same shape as Neo4jEnterpriseCluster.spec.networkPolicy.
serverDefaultCypherLanguage (string)¶
Cypher version a database gets when it is created without one of its own — Neo4j's db.query.default_language. CYPHER_5 or CYPHER_25. Unset, the operator picks once and records it in status.effectiveCypherLanguage: CYPHER_25 for a deployment it creates on a CalVer image, CYPHER_5 on the 5.26 LTS, and whatever an existing deployment already runs — an operator upgrade never changes it. Neo4j fixes a database's language at creation, so this applies only to databases created afterwards; change an existing one with ALTER DATABASE … SET DEFAULT LANGUAGE. Changing the field restarts the servers. CYPHER_25 needs a CalVer image, and nothing is ever written on the LTS (the setting does not exist there). Don't also set db.query.default_language in spec.config; the two are refused when they disagree.
remoteAliasKeystore (RemoteAliasKeystoreSpec)¶
Keystore used to encrypt the credentials of remote database aliases that store
native credentials — including the remote constituents of a
Neo4jCompositeDatabase. Required for that mode
only; aliases using OIDC credential forwarding store no credential and need no
keystore.
remoteAliasKeystore:
secretRef: remote-alias-keystore # keys: keystore.p12, password
keyName: my-key # the keytool -alias
The operator does not generate the keystore; create it with
keytool -genseckey -keyalg aes -keysize 256 -storetype pkcs12. The password
reaches Neo4j as an environment variable sourced from the Secret, so it never
appears in the ConfigMap. See
RemoteAliasKeystoreSpec
for the full description, including why rotating it invalidates every existing
remote alias.
trustedCASecrets ([]TrustedCASecret)¶
CA bundles to add to Neo4j's JVM truststore for outgoing TLS — OIDC providers behind a corporate CA, LDAPS to internal servers, plugin download mirrors, Aura Fleet Management endpoints with private trust.
trustedCASecrets:
- name: corp-oidc-ca # ca.crt is the default key
- name: ldap-internal-ca
key: ldap.pem
Each Secret must contain a PEM-encoded CA certificate (default key ca.crt,
matching what cert-manager-issued Secrets contain). The operator runs an
init container that copies the JDK's default cacerts to a writable JKS,
imports each supplied CA with the Secret name as the keytool alias, and sets
-Djavax.net.ssl.trustStore=/truststore/truststore.jks on the JVM.
The legacy singular spec.auth.trustStore is also folded
into the same JKS at reconcile time. See the
shared TrustedCASecret reference
for full details and a cert-manager example.
extraVolumes / extraVolumeMounts¶
Arbitrary pod volumes + mount points for the Neo4j container. Used when:
- A Neo4j SSL policy references a specific
truststore_path(dbms.ssl.policy.<name>.truststore_path) —trustedCASecretsonly populates the JVM-default truststore, not policy-specific paths. - Custom plugin JARs / configuration files need to live at a specific path.
Mount paths that collide with operator-managed paths (/data, /logs,
/conf, /ssl, /plugins, /truststore, /truststore-ca,
/var/lib/neo4j and standard subdirectories) are rejected by the validator.
extraVolumes:
- name: replica-truststore
secret:
secretName: replica-cluster-ca
extraVolumeMounts:
- name: replica-truststore
mountPath: /var/lib/neo4j/policies/replica
readOnly: true
extraEnvFrom ([]EnvFromSource)¶
Standard Kubernetes pass-through. Projects entire Secrets or ConfigMaps as
environment variables onto the Neo4j container (envFrom). Same semantics as
Neo4jEnterpriseCluster.spec.extraEnvFrom — commonly used to
project cloud credentials for backup seed URIs, plugin tokens, or any
Secret-projected env. Document only the top-level field; nested sub-fields are
the standard core/v1 EnvFromSource shape.
podServiceAccountAnnotations (map[string]string)¶
Binds the Neo4j pod to a cloud role (Workload Identity), so the server can
fetch a seed from cloud storage without a credentials Secret. The operator
creates a ServiceAccount named <name>-neo4j carrying these annotations and
runs the pod under it. That covers an online Neo4jRestore from a backup with
no credentialsSecretRef, and a Neo4jDatabase seedURI. Same field as
Neo4jEnterpriseCluster.spec.podServiceAccountAnnotations.
- Unset (the default), the pod runs under the namespace's
defaultServiceAccount and the operator creates none. - Setting, changing or removing it restarts the pod once, because identity webhooks inject credentials when a pod is created. An online restore waits for that restart.
- Removing it deletes the ServiceAccount once the pod no longer uses it.
- The operator owns only the keys listed; annotations added to the ServiceAccount by hand are kept.
podServiceAccountAnnotations:
eks.amazonaws.com/role-arn: arn:aws:iam::123456789012:role/neo4j-seed # AWS IRSA
# iam.gke.io/gcp-service-account: neo4j-seed@my-project.iam.gserviceaccount.com # GKE WI
Pod scheduling and security (standard Kubernetes pass-throughs)¶
These top-level fields are passed through unchanged to the Neo4j pod spec. Only the top-level field is documented here; their nested sub-fields follow the standard core/v1 shapes.
| Field | Type | Description |
|---|---|---|
affinity |
*corev1.Affinity |
Affinity rules for pod scheduling (node/pod affinity and anti-affinity). |
nodeSelector |
map[string]string |
Node selector for pod scheduling. |
tolerations |
[]corev1.Toleration |
Tolerations for pod scheduling. |
securityContext |
*SecurityContextSpec |
Overrides pod/container security settings (e.g. for OpenShift SCC compatibility). |
nodeSelector:
disktype: ssd
tolerations:
- key: "dedicated"
operator: "Equal"
value: "neo4j"
effect: "NoSchedule"
affinity:
nodeAffinity: {}
securityContext: {}
Status Fields¶
The Neo4jEnterpriseStandalone status provides information about the current state of the deployment.
Primary Status Fields¶
phase (string)¶
Current deployment phase:
Pending: Deployment is being createdReady: Deployment is running and ready for connectionsFailed: Deployment has failed — including spec validation errors and a missing StorageClass (the reason is instatus.message; there is no separateValidationFailedphase)
effectiveCypherLanguage (string)¶
The server default Cypher version the operator resolved (see
spec.serverDefaultCypherLanguage), recorded once so an unset spec never
changes meaning under a running deployment.
ready (boolean)¶
Indicates if the standalone deployment is ready for connections.
lastStartTime (*metav1.Time)¶
Reserved — never populated today. Intended: timestamp of when the standalone deployment was last started.
conditions ([]Condition)¶
Detailed conditions about the deployment state.
endpoints (EndpointStatus)¶
Connection endpoints for the Neo4j instance. The bolt scheme reflects the TLS configuration: bolt+s:// when TLS is enabled, bolt:// when disabled. connectionExamples is populated from spec.service.type and the LoadBalancer-assigned external IP (when applicable).
Endpoints are resolved against the {name}-client Service. {name}-service also resolves (a ClusterIP-only alias) but is deprecated; use {name}-client.
# TLS disabled, ClusterIP
endpoints:
bolt: "bolt://standalone-neo4j-client.default.svc.cluster.local:7687"
http: "http://standalone-neo4j-client.default.svc.cluster.local:7474"
https: "https://standalone-neo4j-client.default.svc.cluster.local:7473"
connectionExamples:
portForward: "kubectl port-forward -n default svc/standalone-neo4j-client 7474:7474 7687:7687"
browserURL: "http://localhost:7474"
boltURI: "bolt://localhost:7687"
neo4jURI: "neo4j://localhost:7687"
pythonExample: |
from neo4j import GraphDatabase
driver = GraphDatabase.driver("bolt://localhost:7687", auth=("neo4j", "<password>"))
javaExample: |
import org.neo4j.driver.*;
Driver driver = GraphDatabase.driver("bolt://localhost:7687", AuthTokens.basic("neo4j", "<password>"));
# TLS enabled (cert-manager) — connection examples use bolt+ssc:// since
# cert-manager-issued certs are typically not trusted by external clients.
endpoints:
bolt: "bolt+s://standalone-neo4j-client.default.svc.cluster.local:7687"
http: "http://standalone-neo4j-client.default.svc.cluster.local:7474"
https: "https://standalone-neo4j-client.default.svc.cluster.local:7473"
connectionExamples:
portForward: "kubectl port-forward -n default svc/standalone-neo4j-client 7473:7473 7687:7687"
browserURL: "https://localhost:7473"
boltURI: "bolt+ssc://localhost:7687"
neo4jURI: "neo4j+ssc://localhost:7687"
version (string)¶
Current Neo4j version running.
podStatus (StandalonePodStatus)¶
Reserved — never populated today (the schema is shown for reference; use kubectl get pod <name>-0 for pod state). Intended: information about the Neo4j pod.
podStatus:
podName: standalone-neo4j-0
podIP: "10.244.0.100"
nodeName: "worker-node-1"
phase: Running
restartCount: 0
databaseStatus (StandaloneDatabaseStatus)¶
Reserved — never populated today (use status.diagnostics.databases instead). Intended: information about the Neo4j database.
| Field | Type | Description |
|---|---|---|
databaseMode |
string |
Database mode (single-node) |
databaseName |
string |
Active database name (usually "neo4j") |
storageSize |
string |
Current storage usage |
connectionCount |
int32 |
Number of active connections |
lastHealthCheck |
*metav1.Time |
When the last health check was performed |
healthStatus |
string |
Current health status |
databaseStatus:
databaseMode: "SINGLE" # Single-node deployment
databaseName: "neo4j"
storageSize: "2.5Gi"
connectionCount: 5
healthStatus: "Healthy"
lastHealthCheck: "2025-01-20T10:30:00Z"
diagnostics (StandaloneDiagnosticsStatus)¶
Live diagnostics collected from SHOW DATABASES, SHOW USERS and SHOW ROLES while the standalone is in Ready phase. On by default; spec.monitoring.enabled: false turns it off. Collected on every reconcile and written to status when something in them changes, or at least every 5 minutes. Collection errors are stored in diagnostics.collectionError and never block reconciliation.
| Field | Type | Description |
|---|---|---|
databases |
[]DatabaseDiagnosticInfo |
Database status from SHOW DATABASES: name, status, requestedStatus, role, default, type (standard, composite, replica, …), access, writer, lastCommittedTxn, replicationLag (always 0 on a standalone) |
users |
[]UserDiagnosticInfo |
Users from SHOW USERS (user, roles, suspended, homeDatabase); a bounded summary — see userCount |
userCount |
int |
Total number of users observed, even when users is truncated |
roles |
[]RoleDiagnosticInfo |
Roles from SHOW ROLES (role, immutable); a bounded summary — see roleCount |
roleCount |
int |
Total number of roles observed, even when roles is truncated |
lastCollected |
*metav1.Time |
When the diagnostics were last written: only when something in them changes, or at least every 5 minutes (database transaction counters do not count as a change) |
collectionError |
string |
Error message if collection failed (empty on success) |
observedGeneration (int64)¶
The most recent generation observed by the controller. Compare with metadata.generation to detect whether the controller has processed the latest spec changes.
Examples¶
Basic Standalone Deployment¶
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jEnterpriseStandalone
metadata:
name: dev-neo4j
namespace: development
spec:
acceptLicenseAgreement: "eval"
image:
repo: neo4j
tag: "5.26-enterprise" # Use specific version
storage:
className: standard
size: "10Gi"
retentionPolicy: Delete # Clean up PVC on deletion
resources:
requests:
memory: "2Gi" # Minimum for Neo4j Enterprise
cpu: "500m"
limits:
memory: "4Gi"
cpu: "2"
auth:
adminSecret: neo4j-admin-secret # Contains username/password
# Optional: Custom Neo4j configuration
config:
server.memory.heap.initial_size: "1G"
server.memory.heap.max_size: "2G"
server.memory.pagecache.size: "1G"
Standalone with LoadBalancer Service¶
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jEnterpriseStandalone
metadata:
name: public-neo4j
namespace: production
spec:
acceptLicenseAgreement: "eval"
image:
repo: neo4j
tag: "5.26-enterprise"
storage:
className: fast-ssd
size: "50Gi"
retentionPolicy: Retain # Keep data on deletion
resources:
requests:
memory: "4Gi"
cpu: "2"
limits:
memory: "8Gi"
cpu: "4"
# LoadBalancer service for external access
service:
type: LoadBalancer
annotations:
# Example for AWS NLB
service.beta.kubernetes.io/aws-load-balancer-type: "nlb"
service.beta.kubernetes.io/aws-load-balancer-backend-protocol: "tcp"
loadBalancerSourceRanges:
- "10.0.0.0/8" # Corporate network
- "192.168.0.0/16" # VPN range
externalTrafficPolicy: Local # Preserve client IPs
auth:
adminSecret: neo4j-admin-secret
# Production configuration
config:
server.memory.heap.initial_size: "2G"
server.memory.heap.max_size: "4G"
server.memory.pagecache.size: "2G"
db.logs.query.enabled: "INFO" # enum: OFF | INFO | VERBOSE (not a boolean)
db.logs.query.threshold: "1s"
# Password policy via Neo4j config keys
dbms.security.auth_minimum_password_length: "12"
Standalone with Ingress¶
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jEnterpriseStandalone
metadata:
name: web-neo4j
namespace: production
spec:
acceptLicenseAgreement: "eval"
image:
repo: neo4j
tag: "5.26-enterprise"
storage:
className: standard
size: "20Gi"
# TLS configuration
tls:
mode: cert-manager
issuerRef:
name: letsencrypt-prod
kind: ClusterIssuer
# Ingress for HTTPS access
service:
ingress:
enabled: true
className: nginx
host: neo4j.example.com
tlsSecretName: neo4j-tls
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/backend-protocol: "HTTPS"
auth:
authenticationProviders: ["native"]
adminSecret: neo4j-admin-secret
Production Standalone with TLS and Plugins¶
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jEnterpriseStandalone
metadata:
name: prod-neo4j-standalone
namespace: production
spec:
acceptLicenseAgreement: "eval"
image:
repo: neo4j
tag: "5.26-enterprise"
storage:
className: fast-ssd
size: "50Gi"
retentionPolicy: Retain # Persist data
resources:
requests:
memory: "4Gi"
cpu: "2"
limits:
memory: "8Gi"
cpu: "4"
tls:
mode: cert-manager
issuerRef:
name: ca-cluster-issuer
kind: ClusterIssuer
auth:
adminSecret: neo4j-admin-secret
service:
type: LoadBalancer
annotations:
service.beta.kubernetes.io/aws-load-balancer-type: nlb
monitoring:
enabled: true
slowQueryThreshold: "1s"
queryLogLevel: "INFO"
obfuscateLiterals: true
config:
server.memory.heap.initial_size: "2G"
server.memory.heap.max_size: "4G"
server.memory.pagecache.size: "2G"
db.logs.query.enabled: "INFO" # enum: OFF | INFO | VERBOSE (not a boolean)
db.logs.query.threshold: "500ms"
dbms.security.auth_minimum_password_length: "12"
---
# Install APOC plugin using Neo4jPlugin CRD
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jPlugin
metadata:
name: prod-apoc-plugin
namespace: production
spec:
clusterRef: prod-neo4j-standalone # References the standalone
name: apoc
version: "5.26.0"
config:
"apoc.export.file.enabled": "true"
"apoc.import.file.enabled": "true"
"apoc.import.file.use_neo4j_config": "true"
---
# Create a database using Neo4jDatabase CRD
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jDatabase
metadata:
name: prod-app-database
namespace: production
spec:
clusterRef: prod-neo4j-standalone # References the standalone
name: appdb
ifNotExists: true
initialData:
source: cypher
cypherStatements:
- "CREATE CONSTRAINT user_email IF NOT EXISTS FOR (u:User) REQUIRE u.email IS UNIQUE"
- "CREATE INDEX user_name IF NOT EXISTS FOR (u:User) ON (u.name)"
Management Commands¶
Basic Operations¶
# Create a standalone deployment
kubectl apply -f standalone-neo4j.yaml
# List standalone deployments
kubectl get neo4jenterprisestandalone
# Describe a standalone deployment
kubectl describe neo4jenterprisestandalone dev-neo4j
# Get logs
kubectl logs -l app=dev-neo4j
# Port forward for local access
kubectl port-forward svc/dev-neo4j-client 7474:7474 7687:7687
Scaling and Updates¶
# Update configuration
kubectl edit neo4jenterprisestandalone dev-neo4j
# Update Neo4j version
kubectl patch neo4jenterprisestandalone dev-neo4j -p '{"spec":{"image":{"tag":"2025.01.0-enterprise"}}}'
# Check status
kubectl get neo4jenterprisestandalone dev-neo4j -o yaml
Database and Plugin Management¶
# Create a database in the standalone instance
kubectl apply -f - <<EOF
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jDatabase
metadata:
name: app-database
spec:
clusterRef: dev-neo4j # References the standalone
name: appdb
ifNotExists: true
initialData:
source: cypher
cypherStatements:
- "CREATE CONSTRAINT user_email IF NOT EXISTS FOR (u:User) REQUIRE u.email IS UNIQUE"
EOF
# Install APOC plugin
kubectl apply -f - <<EOF
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jPlugin
metadata:
name: apoc-plugin
spec:
clusterRef: dev-neo4j # References the standalone
name: apoc
version: "5.26.0"
config:
"apoc.export.file.enabled": "true"
EOF
Backup and Restore¶
# Create a backup
kubectl apply -f - <<EOF
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jBackup
metadata:
name: dev-neo4j-backup
spec:
instanceRef: dev-neo4j # Neo4jEnterpriseStandalone (or Cluster) in this namespace
database: neo4j # or `allDatabases: true`
storage:
type: s3
bucket: my-backup-bucket
path: /backups/dev-neo4j
EOF
# Restore from backup
kubectl apply -f - <<EOF
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jRestore
metadata:
name: restore-dev-neo4j
spec:
instanceRef: dev-neo4j # Target standalone instance
database: neo4j
source:
type: backup
backupRef: dev-neo4j-backup
options:
replaceExisting: true
stopCluster: true # S3 by pod identity: offline unless the standalone sets podServiceAccountAnnotations
EOF
Migration Guide¶
From Neo4jEnterpriseCluster (Single-Node)¶
If you previously used Neo4jEnterpriseCluster with 1 primary and 0 secondaries, migrate to Neo4jEnterpriseStandalone:
Before (no longer supported):
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jEnterpriseCluster
metadata:
name: single-node-cluster
spec:
acceptLicenseAgreement: "eval"
topology:
primaries: 1
secondaries: 0
# ... other config ...
After:
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jEnterpriseStandalone
metadata:
name: single-node-standalone
spec:
acceptLicenseAgreement: "eval"
# ... same config without topology ...
To Neo4jEnterpriseCluster (Clustered)¶
To upgrade from standalone to clustered deployment:
- Create a backup of your standalone deployment
- Deploy a new cluster with minimum topology (2 servers)
- Restore the backup to the new cluster
- Update application connections to the new cluster endpoints
- Delete the old standalone deployment
Troubleshooting¶
Common Issues¶
Deployment Stuck in Pending¶
# Check pod status
kubectl get pods -l app=<standalone-name>
kubectl describe pod <pod-name>
# Check PVC
kubectl get pvc neo4j-data-<standalone-name>-0
kubectl describe pvc neo4j-data-<standalone-name>-0
Validation Errors¶
# Check for validation errors
kubectl describe neo4jenterprisestandalone <name>
# Common validation issues:
# - Invalid Neo4j version (must be 5.26 LTS or a CalVer release: 2025.x, 2026.x, etc.)
# - Clustering configurations in spec.config
# - Invalid storage size format
Connection Issues¶
# Check service endpoints
kubectl get svc -l app.kubernetes.io/instance=<standalone-name>
kubectl describe svc <service-name>
# Check pod status
kubectl get pods -l app=<standalone-name>
kubectl describe pod <standalone-name>-0
# Check pod logs
kubectl logs <standalone-name>-0 -c neo4j
# Test connectivity
kubectl port-forward svc/<service-name> 7474:7474 7687:7687
curl http://localhost:7474
# Test database connectivity
kubectl exec <standalone-name>-0 -c neo4j -- \
cypher-shell -u neo4j -p <password> "RETURN 'Connected!' as status"
Performance Tuning¶
Memory Configuration¶
config:
# Adjust based on available memory
server.memory.heap.initial_size: "2G"
server.memory.heap.max_size: "4G"
server.memory.pagecache.size: "2G"
# For memory-intensive workloads
dbms.memory.transaction.total.max: "1G"
Storage Optimization¶
storage:
className: fast-ssd # Use SSD storage class
size: "50Gi" # Size for your data requirements
# For high IOPS workloads
config:
db.checkpoint.interval.time: "15s"
db.checkpoint.interval.tx: "100000"
Best Practices¶
- Use appropriate resource limits based on your workload
- Enable TLS for production deployments
- Configure backups for data protection
- Monitor query performance with query monitoring
- Use specific Neo4j versions instead of latest tags
- Set proper password policies for security
- Configure resource quotas in production namespaces
- Use correct configuration settings - see Configuration Best Practices
Usage Patterns¶
Development Environment¶
# Minimal development setup
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jEnterpriseStandalone
metadata:
name: dev-neo4j
spec:
acceptLicenseAgreement: "eval"
image:
repo: neo4j
tag: "5.26-enterprise"
storage:
className: standard
size: 5Gi
retentionPolicy: Delete
resources:
requests:
cpu: 200m
memory: 1Gi
limits:
cpu: 1
memory: 2Gi
auth:
adminSecret: dev-auth-secret
Testing with Multiple Databases¶
# Standalone for testing multiple databases
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jEnterpriseStandalone
metadata:
name: test-neo4j
spec:
acceptLicenseAgreement: "eval"
image:
repo: neo4j
tag: "5.26-enterprise"
storage:
className: standard
size: 20Gi
resources:
requests:
memory: 2Gi
cpu: 500m
limits:
memory: 4Gi
cpu: 2
auth:
adminSecret: test-auth-secret
---
# Test database 1
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jDatabase
metadata:
name: test-users-db
spec:
clusterRef: test-neo4j
name: users
ifNotExists: true
---
# Test database 2
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jDatabase
metadata:
name: test-products-db
spec:
clusterRef: test-neo4j
name: products
ifNotExists: true
Migration from Cluster to Standalone¶
# 1. Create backup from cluster
kubectl apply -f - <<EOF
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jBackup
metadata:
name: cluster-migration-backup
spec:
instanceRef: old-cluster # the source Neo4jEnterpriseCluster
database: neo4j
storage:
type: s3
bucket: migration-backups
path: /cluster-to-standalone/
EOF
# 2. Wait for backup completion
kubectl wait --for=condition=Ready neo4jbackup/cluster-migration-backup --timeout=600s
# 3. Create the standalone, wait for Ready, then restore via Neo4jRestore
kubectl apply -f - <<EOF
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jEnterpriseStandalone
metadata:
name: migrated-standalone
spec:
acceptLicenseAgreement: "eval"
# ... standalone configuration ...
EOF
kubectl wait --for=condition=Ready neo4jenterprisestandalone/migrated-standalone --timeout=600s
# 4. Restore the backup into the new standalone
kubectl apply -f - <<EOF
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jRestore
metadata:
name: migrated-standalone-restore
spec:
instanceRef: migrated-standalone # Neo4jEnterpriseStandalone
database: neo4j
source:
type: backup
backupRef: cluster-migration-backup
options:
replaceExisting: true # the new standalone already has a default `neo4j` database
stopCluster: true # S3 by pod identity: offline unless the standalone sets podServiceAccountAnnotations
EOF
Best Practices¶
- Resource Allocation: Use at least 1.5Gi memory for Neo4j Enterprise database operations
- Storage: Use fast SSD storage classes for production workloads
- Authentication: Always use adminSecret for secure credential management
- TLS: Enable TLS for production deployments using cert-manager
- Backup Strategy: Implement regular backups with appropriate retention policies
- Plugin Management: Use Neo4jPlugin CRD for plugin installation
- Database Management: Use Neo4jDatabase CRD for automated database creation and schema setup
- Monitoring: Enable query monitoring for performance insights
- Configuration: Use Neo4j 5.26+ configuration syntax (server.* instead of dbms.connector.*)
- Version Pinning: Always use specific version tags instead of latest
When to Use Cluster Instead¶
Consider migrating to Neo4jEnterpriseCluster when you need:
- High Availability: Automatic failover and redundancy
- Horizontal Scaling: Multiple servers for read/write scaling
- Multi-Database Topologies: Different databases with optimized distribution
- Production Workloads: Enhanced reliability and performance
- Load Distribution: Separation of read and write workloads
For more information: