Skip to content

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.name is 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}-config containing neo4j.conf and health.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

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 Neo4jEnterpriseCluster instead.

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.

acceptLicenseAgreement: "eval"   # "yes" (commercial) or "eval" (30-day evaluation)

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.

resources:
  requests:
    memory: "2Gi"
    cpu: "500m"
  limits:
    memory: "4Gi"
    cpu: "2"

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 listeners
  • server.http.listen_address - HTTP endpoints
  • NEO4J_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 shared TLSSpec but has no effect on Neo4jEnterpriseStandalone — single-server deployments have no intra-cluster traffic, so there's no cluster SSL policy to govern. Setting it to false on a standalone raises a ValidationWarning event saying so (true is the CRD default, so it is not warned about); the standalone is still accepted.

Note on certificateSecret: the field is present on the shared TLSSpec but is never read: the operator always uses the cert-manager Secret {name}-tls-secret. A ValidationWarning event is raised whenever it is set, whatever mode is.

auth (AuthSpec)

Authentication configuration.

auth:
  authenticationProviders: ["native"]
  adminSecret: neo4j-admin-secret

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:

  1. Updates the standalone StatefulSet with NEO4J_PLUGINS environment variable
  2. Adds plugin-specific configuration as NEO4J_* environment variables
  3. Triggers a rolling restart to apply plugin changes
  4. 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.

audit:
  enabled: true   # secure-by-default: redacts query literals

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.

networkPolicy:
  enabled: true   # opt-in; requires a CNI that enforces 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.

serverDefaultCypherLanguage: CYPHER_25   # CalVer only

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) — trustedCASecrets only 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.

extraEnvFrom:
  - secretRef:
      name: aws-backup-creds

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 default ServiceAccount 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 created
  • Ready: Deployment is running and ready for connections
  • Failed: Deployment has failed — including spec validation errors and a missing StorageClass (the reason is in status.message; there is no separate ValidationFailed phase)

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:

  1. Create a backup of your standalone deployment
  2. Deploy a new cluster with minimum topology (2 servers)
  3. Restore the backup to the new cluster
  4. Update application connections to the new cluster endpoints
  5. 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

  1. Use appropriate resource limits based on your workload
  2. Enable TLS for production deployments
  3. Configure backups for data protection
  4. Monitor query performance with query monitoring
  5. Use specific Neo4j versions instead of latest tags
  6. Set proper password policies for security
  7. Configure resource quotas in production namespaces
  8. 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

  1. Resource Allocation: Use at least 1.5Gi memory for Neo4j Enterprise database operations
  2. Storage: Use fast SSD storage classes for production workloads
  3. Authentication: Always use adminSecret for secure credential management
  4. TLS: Enable TLS for production deployments using cert-manager
  5. Backup Strategy: Implement regular backups with appropriate retention policies
  6. Plugin Management: Use Neo4jPlugin CRD for plugin installation
  7. Database Management: Use Neo4jDatabase CRD for automated database creation and schema setup
  8. Monitoring: Enable query monitoring for performance insights
  9. Configuration: Use Neo4j 5.26+ configuration syntax (server.* instead of dbms.connector.*)
  10. 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: