Neo4jPlugin API Reference¶
The Neo4jPlugin Custom Resource Definition (CRD) provides automated plugin installation and management for both Neo4j Enterprise clusters and standalone deployments.
Overview¶
- API Version:
neo4j.neo4j.com/v1beta1 - Kind:
Neo4jPlugin - Target Deployments: Both
Neo4jEnterpriseClusterandNeo4jEnterpriseStandalone - Installation Method: Neo4j's
NEO4J_PLUGINSenvironment variable approach - Supported Plugins: APOC, Graph Data Science, Bloom, GraphQL, GenAI, N10s, and custom plugins
- Note: Fleet Management is managed via
spec.auraFleetManagementon the cluster/standalone CRD, not viaNeo4jPlugin. Both coexist without conflict. - Automatic Configuration: Plugin-specific settings and security policies
Architecture¶
Universal Compatibility: The Neo4jPlugin CRD works seamlessly with both deployment architectures:
- Cluster Support: Updates
{cluster-name}-serverStatefulSet with plugin configuration - Standalone Support: Updates
{standalone-name}StatefulSet with plugin configuration - Automatic Detection: Controller automatically identifies target deployment type
- Rolling Updates: Triggers controlled restarts to apply plugin changes
- Environment Variable Method: Uses Neo4j's recommended
NEO4J_PLUGINSinstallation approach
Related Resources¶
Neo4jEnterpriseCluster- Target cluster deploymentsNeo4jEnterpriseStandalone- Target standalone deploymentsNeo4jDatabase- Create databases that use plugin functionality- Plugin Examples - Detailed usage examples
Plugin Installation Process¶
The Neo4jPlugin controller implements Neo4j's recommended installation approach:
Installation Steps¶
- Target Discovery: Automatically detects whether
clusterRefpoints to a cluster or standalone - Plugin Collection: Gathers main plugin and all dependencies into a unified list
- Environment Variable Setup: Merges plugin names into the existing
NEO4J_PLUGINSJSON array (additive — does not overwrite entries added by other controllers such as the Aura Fleet Management reconciler) - Configuration Application: Adds plugin-specific settings as
NEO4J_*environment variables - StatefulSet Update: Patches the target StatefulSet with new configuration
- Rolling Restart: Triggers controlled pod restarts to apply changes
- Verification: Confirms plugin installation and updates status
Multi-plugin coexistence: The plugin controller, the cluster/standalone controller, and the Aura Fleet Management reconciler all use an additive merge strategy for
NEO4J_PLUGINS. Installing APOC viaNeo4jPluginand enabling Fleet Management viaspec.auraFleetManagementsimultaneously results in["apoc","fleet-management"]— neither entry is overwritten on subsequent reconciles.
Environment Variable Mapping¶
Example Configuration (APOC):
Applied Environment Variables (APOC):
env:
- name: NEO4J_PLUGINS
value: '["apoc"]'
- name: NEO4J_APOC_EXPORT_FILE_ENABLED
value: 'true'
- name: NEO4J_APOC_IMPORT_FILE_ENABLED
value: 'true'
Notes:
- APOC settings are applied via environment variables in Neo4j 5.26+
- Bloom/GDS/GenAI settings are applied via ConfigMap (standalone) or runtime configuration (cluster)
- Automatic dependency resolution and security defaults are applied as needed
API Version¶
Spec Fields¶
| Field | Type | Required | Description |
|---|---|---|---|
clusterRef |
string |
✅ | Name of target Neo4jEnterpriseCluster or Neo4jEnterpriseStandalone |
name |
string |
✅ | Plugin name (e.g., "apoc", "graph-data-science") |
version |
string |
✅ | Plugin version to install (must match Neo4j version compatibility) |
enabled |
boolean |
❌ | Enable the plugin (default: true) |
installMode |
string |
❌ | Managed (default) — operator adds plugin to NEO4J_PLUGINS. PreBaked — operator only writes config; JAR must be in a custom image. VerifiedDownload — operator injects an init container that downloads source.url and verifies it against source.checksum before Neo4j starts. See Supply-chain. |
source |
PluginSource |
❌ | Plugin source configuration (default: official repository). Required when installMode: VerifiedDownload. Ignored when installMode: PreBaked. |
dependencies |
[]PluginDependency |
❌ | Plugin dependencies (automatically resolved) |
config |
map[string]string |
❌ | Plugin-specific configuration (becomes NEO4J_* env vars) |
security |
PluginSecurity |
❌ | Security settings and procedure restrictions |
resources |
PluginResourceRequirements |
❌ | Reserved — no effect today. Declared (memoryLimit, cpuLimit, threadPoolSize) and syntax-checked by the validator, but no controller or builder reads it: nothing is allocated or limited. Size the Neo4j pods through the cluster/standalone spec.resources instead. A ValidationWarning event is raised when it is set. |
PluginSource¶
| Field | Type | Description |
|---|---|---|
type |
string |
Source type: "official", "community", "custom", "url" (default: official) |
url |
string |
Direct URL for "url" and "custom" source types. Must be https:// — the controller-side validator rejects http://, file://, and every other scheme (plugin JARs are downloaded over the network and a non-https scheme has no transport integrity). Host internal plugins on an https mirror, e.g. with a cert-manager certificate. |
checksum |
string |
Checksum for verification. Required by the controller-side validator for type: url and type: custom. Must match ^(sha256:[a-fA-F0-9]{64}\|sha512:[a-fA-F0-9]{128})$ (hex digits of either case). SHA1 and MD5 are rejected. See Supply-chain. |
authSecret |
string |
Secret containing auth for private repositories/URLs. Consumed only by installMode: VerifiedDownload (keys token or header — see Supply-chain). |
registry |
PluginRegistry |
Reserved — no effect today. Never read by any controller; a custom source is fetched from source.url, which (with checksum) is required for type: url and type: custom regardless of registry. A ValidationWarning event is raised when it is set, and another when registry.tls is set. |
PluginRegistry¶
Reserved — no effect today.
source.registryand everything under it (includingtls) is accepted by the schema but never read, and aValidationWarningevent says so when it is set; see theregistryrow above.
| Field | Type | Required | Description |
|---|---|---|---|
url |
string |
✅ | Registry URL |
authSecret |
string |
❌ | Authentication secret |
tls |
RegistryTLSConfig |
❌ | TLS configuration |
RegistryTLSConfig¶
| Field | Type | Description |
|---|---|---|
insecureSkipVerify |
boolean |
Skip TLS verification |
caSecret |
string |
CA certificate secret |
PluginDependency¶
| Field | Type | Description |
|---|---|---|
name |
string |
Dependency plugin name |
versionConstraint |
string |
Version constraint (e.g., ">=5.26.0") |
optional |
boolean |
Whether dependency is optional |
PluginSecurity¶
| Field | Type | Description |
|---|---|---|
allowedProcedures |
[]string |
Becomes dbms.security.procedures.allowlist (and …unrestricted unless sandbox: true). An allowlist: plugin procedures and functions it does not match are not loaded at all, server-wide, and fail as Unknown function. |
deniedProcedures |
[]string |
List of denied procedures/functions |
securityPolicy |
string |
Security policy: one of "strict", "moderate", "permissive" (any other value fails validation and the plugin goes to phase Invalid). Reserved — no effect today: the value is validated but not used to change any Neo4j setting (restrict procedures with allowedProcedures / deniedProcedures). A ValidationWarning event is raised when it is set. |
sandbox |
boolean |
Enable sandbox mode: with allowedProcedures set, the list is applied as an allowlist only; when false (default) the same list is also written to dbms.security.procedures.unrestricted. |
Status Fields¶
| Field | Type | Description |
|---|---|---|
conditions |
[]metav1.Condition |
A single Ready condition derived from phase (Ready → True; Failed/Invalid → False; Pending/Waiting/Installing → Unknown) |
phase |
string |
Current phase: "Pending", "Installing", "Ready", "Failed", "Waiting", "Invalid" (spec failed validation; not retried until the CR is edited) |
message |
string |
Human-readable status message |
installedVersion |
string |
The version the operator last installed successfully: spec.version as it was when the plugin reached Ready (the version requested, not read back from the running plugin). Left unchanged while a later attempt is Installing or Failed, so it always names the last install that worked |
installationTime |
*metav1.Time |
When the plugin was first recorded as installed at installedVersion: set on reaching Ready, not touched by later reconciles or by Ready → Installing → Ready cycles at the same version. A different spec.version is a new installation and restarts it |
health |
*PluginHealth |
Reserved — never populated today. Intended: plugin health and performance information |
usage |
*PluginUsage |
Reserved — never populated today. Intended: plugin usage statistics |
observedGeneration |
int64 |
Generation of the most recently observed spec |
PluginHealth¶
Reserved — never populated today (also applies to
PluginPerformanceandPluginUsagebelow).
Plugin health and performance metrics.
| Field | Type | Description |
|---|---|---|
status |
string |
Plugin health status |
lastHealthCheck |
*metav1.Time |
Last health check timestamp |
errors |
[]string |
Error messages from health checks |
performance |
*PluginPerformance |
Performance metrics |
PluginPerformance¶
Plugin performance statistics.
| Field | Type | Description |
|---|---|---|
memoryUsage |
string |
Current memory usage |
cpuUsage |
string |
Current CPU usage |
executionCount |
int64 |
Number of procedure executions |
avgExecutionTime |
string |
Average execution time |
PluginUsage¶
Plugin usage analytics.
| Field | Type | Description |
|---|---|---|
proceduresCalled |
map[string]int64 |
Count of procedure calls by name |
lastUsed |
*metav1.Time |
Last time plugin was used |
usageFrequency |
string |
Usage frequency classification |
Supply-chain¶
The Neo4j Enterprise Docker entrypoint resolves NEO4J_PLUGINS at pod
startup. For APOC core that's deterministic — the JAR is bundled in
the image and just gets copied to /plugins/. For every other plugin
(graph-data-science, bloom, genai, n10s, graphql, apoc-extended)
the entrypoint downloads from the internet on every pod start, which
has three production consequences:
- Non-reproducibility — a restart can pull a different artifact than the one originally validated.
- Egress requirement — air-gapped clusters cannot permit the outbound HTTP.
- Supply-chain exposure — every pod start is an unauthenticated fetch.
The operator offers two postures.
installMode: PreBaked (recommended for production)¶
Build a custom Neo4j image with the plugin JAR copied into /plugins/
(or /var/lib/neo4j/plugins/), reference that image from
spec.image.repo/tag on the cluster or standalone CR, and set
installMode: PreBaked on the Neo4jPlugin. The operator does not
touch NEO4J_PLUGINS — no runtime fetch happens — but still writes the
plugin's required configuration (security allowlists, unrestricted
procedures, ConfigMap entries for standalone). You get the declarative
CRD UX and a pinned, signed, scannable artifact.
installMode: Managed with a checksum (when you must download)¶
When the JAR must be fetched at runtime, the validator requires a
source.checksum for any source.type: url or source.type: custom.
The checksum format is enforced:
sha256:followed by exactly 64 hex characters, orsha512:followed by exactly 128 hex characters.
SHA1, MD5, and unprefixed hex are rejected. SHA1/MD5 because they are not collision-resistant; unprefixed hex because verification tooling should never have to guess the algorithm.
Honest limitation: the upstream Neo4j Docker entrypoint does not
consume source.checksum at download time. The operator records the
field for audit and exposes it on the StatefulSet, but enforcement at
the moment of download requires either (a) pinning to PreBaked or (b)
the VerifiedDownload mode described next.
installMode: VerifiedDownload (verified download via init container)¶
When installMode: VerifiedDownload is set, the operator injects an init
container into the target StatefulSet's pod template. The init container
downloads spec.source.url, computes the SHA256/SHA512 of the downloaded
file, compares it against spec.source.checksum, and writes the JAR to
the shared /plugins emptyDir before Neo4j starts. NEO4J_PLUGINS
is not mutated for this plugin (same skip semantics as PreBaked) —
the upstream entrypoint's own download path is bypassed entirely, so it
can't race the verified JAR.
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jPlugin
spec:
clusterRef: my-cluster
name: graph-data-science
version: "2.13.0"
installMode: VerifiedDownload
source:
type: url
url: https://github.com/neo4j/graph-data-science/releases/download/2.13.0/neo4j-graph-data-science-2.13.0.jar
checksum: sha256:e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855
Failure mode: on checksum mismatch the init container exits non-zero,
the pod stays Pending, and kubectl describe pod shows the failure on
the init container's state.terminated.message. Fix the URL or checksum
and reconcile — the next pod spawn re-runs the init container.
Authenticated mirrors are supported via spec.source.authSecret.
The named Secret should carry either a token key (used as
Authorization: Bearer <token>) or a header key (used verbatim as the
full Authorization: header value). Mounted at /etc/plugin-auth and
consumed by the init script.
Internal CAs are supported via the owning cluster's (or standalone's)
spec.trustedCASecrets list. Each Secret's ca.crt (or the per-Secret
Key override) is mounted under /etc/plugin-ca; the init script
concatenates the certificates into a single CA bundle and points curl at
it via --cacert.
Init container image defaults to curlimages/curl:8.5.0. Override
via the Helm chart's pluginInitContainer.image value when installing
into air-gapped clusters that need a mirrored image.
Limitations:
spec.source.typemust beurlorcustom— the entrypoint'sofficial/communitytypes resolve via an internal manifest the user can't point at a verifiable URL, so the API server rejects them at apply time (a CRD validation rule — the operator has no webhooks).spec.dependenciesare rejected on a VerifiedDownload plugin — mixed install paths in a single CR confuse the supply-chain story. Create each dependency as its ownNeo4jPluginCR with its ownsource.url+checksum.- Every pod restart re-runs the init container, which re-downloads the JAR. For large JARs (GDS ≈ 30 MB) this is bandwidth-wasteful.
Duplicate-CR protection (all install modes)¶
Two Neo4jPlugin CRs in the same namespace that target the same
spec.clusterRef with the same spec.name would race on the
same /plugins directory and the same NEO4J_PLUGINS env value — one
controller adds, the other removes, restart cycle. The reconciler
detects this and refuses to install the duplicate:
- The oldest CR (by
creationTimestamp) keeps reconciling normally. UID is the tiebreaker on identical timestamps. - The newer duplicate is marked
status.phase=Failedwith a message naming the older CR, and aPluginDuplicateWarning Event is emitted. It stops reconciling until the older CR is deleted. - A duplicate that's mid-delete (DeletionTimestamp set) doesn't block its replacement — a stuck finalizer on the older CR can't lock out the survivor.
Action when you see phase=Failed with a duplicate message: delete
the unwanted CR. The surviving CR reconciles on its next watch event
(triggered by the deletion) and takes ownership.
Examples¶
APOC Plugin for Cluster¶
Install APOC plugin on a Neo4jEnterpriseCluster:
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jPlugin
metadata:
name: cluster-apoc-plugin
namespace: default
spec:
# References a Neo4jEnterpriseCluster
clusterRef: my-cluster
# Plugin identification
name: apoc
version: "5.26.0" # Must match Neo4j version
enabled: true
# Plugin source (official Neo4j repository)
source:
type: official
# APOC-specific configuration (becomes NEO4J_APOC_* env vars)
config:
"apoc.export.file.enabled": "true"
"apoc.import.file.enabled": "true"
"apoc.import.file.use_neo4j_config": "true"
"apoc.trigger.enabled": "true"
# Security configuration
security:
allowedProcedures:
- "apoc.*"
securityPolicy: "permissive" # strict | moderate | permissive (validated only; no runtime effect today)
Result: Updates my-cluster-server StatefulSet with:
NEO4J_PLUGINS=["apoc"]NEO4J_APOC_EXPORT_FILE_ENABLED=trueNEO4J_APOC_IMPORT_FILE_ENABLED=true- Security settings for APOC procedures
Graph Data Science Plugin for Standalone¶
Install GDS plugin with dependencies on a Neo4jEnterpriseStandalone:
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jPlugin
metadata:
name: standalone-gds-plugin
namespace: default
spec:
# References a Neo4jEnterpriseStandalone
clusterRef: my-standalone
# Plugin identification
name: graph-data-science
version: "2.10.0"
enabled: true
# Plugin source - official Neo4j repository
source:
type: official
# Plugin dependencies (automatically included in installation)
dependencies:
- name: apoc
versionConstraint: ">=5.26.0"
optional: false
# GDS-specific configuration. Mount the license file at /licenses/gds.license
# via the cluster/standalone spec.extraVolumes + spec.extraVolumeMounts
# (e.g. from a Secret named gds-license-secret).
config:
"gds.enterprise.license_file": "/licenses/gds.license"
"gds.procedure.allowlist": "gds.*"
"gds.graph.store.max_size": "2GB"
# Security configuration
security:
allowedProcedures:
- "gds.*"
- "apoc.load.*" # APOC dependency procedures
securityPolicy: "strict" # strict | moderate | permissive (validated only; no runtime effect today)
sandbox: false # GDS requires full access
# Reserved — validated but not applied today. Size GDS memory/CPU via the
# standalone's own spec.resources and spec.config instead.
resources:
memoryLimit: "2Gi"
cpuLimit: "1"
threadPoolSize: 8
Result: Updates my-standalone StatefulSet with:
NEO4J_PLUGINS=["apoc", "graph-data-science"](dependencies included)- GDS-specific environment variables
- Security settings for both APOC and GDS procedures
(spec.resources on the Neo4jPlugin does not allocate anything — see the field table.)
Custom Plugin Example¶
Install a plugin from a custom (private) location. type: custom needs an https url and a checksum; authSecret (keys token or header) is used by installMode: VerifiedDownload:
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jPlugin
metadata:
name: custom-plugin
spec:
clusterRef: my-cluster
name: my-custom-plugin
version: "1.0.0"
installMode: VerifiedDownload
# Custom source (url + checksum are required)
source:
type: custom
url: "https://my-registry.example.com/plugins/my-custom-plugin-1.0.0.jar"
checksum: "sha256:abcd1234567890abcd1234567890abcd1234567890abcd1234567890abcd1234"
authSecret: registry-credentials
# Security settings
security:
allowedProcedures:
- "custom.*"
sandbox: true
URL Plugin Example¶
Install a plugin directly from a URL:
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jPlugin
metadata:
name: url-plugin
spec:
clusterRef: my-cluster
name: direct-download-plugin
version: "2.0.0"
# Direct URL source with checksum verification
source:
type: url
url: "https://example.com/plugins/my-plugin-2.0.0.jar"
checksum: "sha256:abcd1234567890abcd1234567890abcd1234567890abcd1234567890abcd1234"
Supported Plugins¶
Official Neo4j Plugins¶
| Plugin | Name | Description | Configuration Method | Automatic Security |
|---|---|---|---|---|
| APOC | apoc |
Awesome Procedures on Cypher | Environment Variables | ❌ Manual setup |
| APOC Extended | apoc-extended |
Extended APOC procedures | Environment Variables | ❌ Manual setup |
| Graph Data Science | graph-data-science |
Advanced graph algorithms | Neo4j Config + Security | ✅ Auto-configured |
| Neo4j Streams | streams |
Kafka/Pulsar integration | Neo4j Config | ❌ Manual setup |
| GraphQL | graphql |
GraphQL endpoint | Neo4j Config | ❌ Manual setup |
Enterprise Plugins¶
| Plugin | Name | Description | License Required | Automatic Security |
|---|---|---|---|---|
| Bloom | bloom |
Graph visualization | ✅ Commercial License | ✅ Auto-configured |
| GenAI | genai |
AI/ML integration | ✅ Commercial License | ❌ Manual setup |
Automatic Security Configuration¶
Some plugins require specific security settings to function properly. The operator automatically applies these settings even when no user configuration is provided.
Plugins with Automatic Security¶
Bloom Plugin:
- Automatically applies required security settings for proper operation
- No manual configuration needed for basic functionality
- Automatically configured settings:
NEO4J_DBMS_SECURITY_PROCEDURES_UNRESTRICTED=bloom.*NEO4J_DBMS_SECURITY_HTTP_AUTH_ALLOWLIST=/,/browser.*,/bloom.*NEO4J_SERVER_UNMANAGED_EXTENSION_CLASSES=com.neo4j.bloom.server=/bloom
Graph Data Science Plugin:
- Automatically applies default security settings
- User security configuration can override defaults
- Automatically configured settings:
dbms.security.procedures.unrestricted=gds.*anddbms.security.procedures.allowlist=gds.*(additive — merged with, never replacing, existing values)
Examples with Automatic Security¶
Bloom Plugin (Zero Configuration):
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jPlugin
metadata:
name: bloom-plugin
spec:
clusterRef: my-cluster
name: bloom
version: "2.15.0"
# No config or security section needed
# All required security settings applied automatically
GDS Plugin with Custom Security:
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jPlugin
metadata:
name: gds-plugin
spec:
clusterRef: my-cluster
name: graph-data-science
version: "2.10.0"
# User security settings override automatic ones
security:
sandbox: true # Uses allowlist instead of unrestricted
allowedProcedures: ["gds.*", "apoc.load.*"]
# Results in: NEO4J_DBMS_SECURITY_PROCEDURES_ALLOWLIST=gds.*,apoc.load.*
Automatic vs Manual Security Configuration:
| Configuration Type | Applies When | Environment Variables | Override Behavior |
|---|---|---|---|
| Automatic | No user security section |
Applied automatically | Overridden by user config |
| User-Provided | User defines security section |
User settings + automatic defaults | User settings take precedence |
| Mixed | User partially configures security | Automatic + user settings merged | User settings override matching keys |
Community Plugins¶
| Plugin | Name | Description | Configuration |
|---|---|---|---|
| Neo Semantics (N10s) | n10s |
RDF/ontology support | Neo4j Config |
| Custom Plugins | custom |
User-defined plugins | Flexible |
Plugin-Specific Configuration¶
APOC (Environment Variables):
config:
"apoc.export.file.enabled": "true"
"apoc.import.file.enabled": "true"
"apoc.trigger.enabled": "true"
"apoc.jobs.pool.num_threads": "4"
Graph Data Science (Neo4j Config):
config:
"gds.enterprise.license_file": "/licenses/gds.license"
"gds.graph.store.max_size": "8GB"
"gds.procedure.allowlist": "gds.*"
security:
allowedProcedures:
- "gds.*"
- "apoc.load.*"
Bloom (Automatic Security Configuration):
# Minimal configuration - security settings applied automatically.
# Mount the license file at /licenses/bloom.license via the cluster/standalone
# spec.extraVolumes + spec.extraVolumeMounts (e.g. from a Secret named
# bloom-license-secret).
config:
"dbms.bloom.license_file": "/licenses/bloom.license"
# Automatically applied by operator:
# - NEO4J_DBMS_SECURITY_PROCEDURES_UNRESTRICTED=bloom.*
# - NEO4J_DBMS_SECURITY_HTTP_AUTH_ALLOWLIST=/,/browser.*,/bloom.*
# - NEO4J_SERVER_UNMANAGED_EXTENSION_CLASSES=com.neo4j.bloom.server=/bloom
Plugin Status Phases¶
- Pending: Plugin resource created, waiting for processing
- Waiting: Waiting for the deployment to be ready — on a cluster, also while any server is unavailable (
Degraded), since installing restarts every server - Installing: Plugin installation in progress
- Ready: Plugin successfully installed and active
- Failed: Plugin installation failed (also set on the newer of two duplicate
Neo4jPluginCRs) - Invalid: The spec failed validation (for example an unsupported
securityPolicy, a missingsource.url/checksum, or a non-https URL); the controller does not requeue until the CR is edited
Supported Plugin Sources¶
Official Repository¶
Neo4j's official plugin repository (recommended for production):
- APOC (Awesome Procedures On Cypher)
- Neo4j Streams
- Neo4j GraphQL
Community Repository¶
Community-maintained plugins:
- Graph Data Science (GDS)
- Additional APOC extensions
- Third-party plugins
Custom Registry¶
Private plugin registries with authentication support.
Direct URL¶
Direct download from URLs with checksum verification.
Installation Workflow¶
The Neo4jPlugin controller follows this comprehensive workflow:
Phase 1: Validation and Discovery¶
- Target Validation: Verifies
clusterRefpoints to existing cluster or standalone - Plugin Validation: Checks plugin name, version compatibility, and source availability
- Dependency Analysis: Resolves plugin dependencies and version constraints
- Conflict Detection: Identifies conflicts with existing plugins
Phase 2: Configuration Preparation¶
- Plugin Collection: Assembles main plugin and dependencies into unified list
- Environment Variable Mapping: Converts plugin config to
NEO4J_*environment variables - Security Configuration: Applies plugin-specific security settings
Phase 3: Deployment¶
- StatefulSet Update: Patches target StatefulSet with plugin configuration
- Rolling Restart: Initiates controlled pod restart sequence
- Health Monitoring: Tracks pod restart progress and Neo4j startup
- Installation Verification: Confirms plugin loading via Neo4j procedures
Phase 4: Status and Monitoring¶
- Status Update: Sets plugin phase to "Ready" and records installation time
- Health Tracking: Reports the phase and message (the
health/usagestatus blocks are reserved and not populated today) - Error Handling: Captures and reports installation failures
- Dependency Tracking: Maintains dependency relationships
Example Installation Timeline¶
# Plugin creation
kubectl apply -f apoc-plugin.yaml
# Phase progression
# 0s: Phase: Pending
# 5s: Phase: Installing (StatefulSet updated)
# 30s: Phase: Installing (pods restarting)
# 60s: Phase: Ready (plugin verified)
Configuration Examples by Plugin Type¶
APOC Plugin (Environment Variables):
# Input configuration
config:
"apoc.export.file.enabled": "true"
"apoc.import.file.enabled": "true"
"apoc.trigger.enabled": "true"
# Applied environment variables
env:
- name: NEO4J_PLUGINS
value: '["apoc"]'
- name: NEO4J_APOC_EXPORT_FILE_ENABLED
value: 'true'
- name: NEO4J_APOC_IMPORT_FILE_ENABLED
value: 'true'
- name: NEO4J_APOC_TRIGGER_ENABLED
value: 'true'
Graph Data Science (Environment + Config):
# Input configuration
config:
"gds.enterprise.license_file": "/licenses/gds.license"
"gds.graph.store.max_size": "4GB"
security:
allowedProcedures: ["gds.*", "apoc.*"]
# Applied configuration
env:
- name: NEO4J_PLUGINS
value: '["apoc", "graph-data-science"]'
- name: NEO4J_GDS_ENTERPRISE_LICENSE_FILE
value: '/licenses/gds.license'
- name: NEO4J_GDS_GRAPH_STORE_MAX_SIZE
value: '4GB'
- name: NEO4J_DBMS_SECURITY_PROCEDURES_UNRESTRICTED
value: 'gds.*,apoc.*'
Multiple Plugins with Dependencies:
# Multiple Neo4jPlugin resources
# Result: Combined environment variables
env:
- name: NEO4J_PLUGINS
value: '["apoc", "graph-data-science", "streams"]'
- name: NEO4J_APOC_EXPORT_FILE_ENABLED
value: 'true'
- name: NEO4J_GDS_ENTERPRISE_LICENSE_FILE
value: '/licenses/gds.license'
- name: NEO4J_STREAMS_SINK_TOPIC_CYPHER_NODES
value: 'CREATE (n:Node {id: event.id})'
Advanced Plugin Configurations¶
Custom Plugin from URL¶
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jPlugin
metadata:
name: custom-plugin
spec:
clusterRef: my-cluster
name: my-custom-plugin
version: "1.0.0"
# Custom plugin source
source:
type: url
url: "https://my-registry.example.com/plugins/my-plugin-1.0.0.jar"
checksum: "sha256:abcd1234567890abcd1234567890abcd1234567890abcd1234567890abcd1234"
authSecret: custom-registry-credentials # only used with installMode: VerifiedDownload
# Custom configuration
config:
"custom.plugin.setting1": "value1"
"custom.plugin.setting2": "value2"
# Security restrictions
security:
allowedProcedures:
- "custom.*"
securityPolicy: "strict" # strict | moderate | permissive (validated only)
sandbox: true
Plugin from a Private Mirror (VerifiedDownload)¶
Authenticated mirrors use source.authSecret with installMode: VerifiedDownload; the Secret carries a token key (sent as Authorization: Bearer <token>) or a header key. Trust for an internal CA comes from the cluster's spec.trustedCASecrets.
apiVersion: v1
kind: Secret
metadata:
name: private-registry-auth
type: Opaque
stringData:
token: <registry-access-token>
---
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jPlugin
metadata:
name: private-plugin
spec:
clusterRef: enterprise-cluster
name: enterprise-plugin
version: "2.0.0"
installMode: VerifiedDownload
source:
type: custom
url: "https://private-registry.company.com/plugins/enterprise-plugin-2.0.0.jar"
checksum: "sha256:abcd1234567890abcd1234567890abcd1234567890abcd1234567890abcd1234"
authSecret: private-registry-auth
Production Plugin Setup with Monitoring¶
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jPlugin
metadata:
name: production-apoc
labels:
environment: production
plugin-type: essential
spec:
clusterRef: prod-cluster
name: apoc
version: "5.26.0"
# Production configuration
config:
"apoc.export.file.enabled": "true"
"apoc.import.file.enabled": "false" # Disabled for security
"apoc.trigger.enabled": "true"
"apoc.jobs.pool.num_threads": "8"
"apoc.spatial.geocode.provider": "osm"
# Enhanced security
security:
allowedProcedures:
- "apoc.export.*"
- "apoc.trigger.*"
- "apoc.periodic.*"
- "apoc.meta.*"
securityPolicy: "strict" # strict | moderate | permissive (validated only)
sandbox: false
# Reserved — validated but not applied today (size the Neo4j pods via the
# cluster's spec.resources instead)
resources:
memoryLimit: "512Mi"
cpuLimit: "200m"
threadPoolSize: 8
Multi-Plugin Setup for Analytics Workload¶
# APOC Foundation
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jPlugin
metadata:
name: analytics-apoc
spec:
clusterRef: analytics-cluster
name: apoc
version: "5.26.0"
config:
"apoc.export.file.enabled": "true"
"apoc.import.file.enabled": "true"
"apoc.periodic.enabled": "true"
---
# Graph Data Science for Analytics
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jPlugin
metadata:
name: analytics-gds
spec:
clusterRef: analytics-cluster
name: graph-data-science
version: "2.10.0"
dependencies:
- name: apoc
versionConstraint: "5.26.0"
optional: false
config:
# Mount the license file at /licenses/gds.license via the cluster/standalone
# spec.extraVolumes + spec.extraVolumeMounts (e.g. from a Secret named
# gds-enterprise-license).
"gds.enterprise.license_file": "/licenses/gds.license"
"gds.graph.store.max_size": "16GB"
"gds.procedure.allowlist": "gds.*"
resources: # reserved — validated but not applied today
memoryLimit: "8Gi"
cpuLimit: "4"
threadPoolSize: 16
---
# Neo4j Streams for Real-time Data
apiVersion: neo4j.neo4j.com/v1beta1
kind: Neo4jPlugin
metadata:
name: analytics-streams
spec:
clusterRef: analytics-cluster
name: streams
version: "5.26.0"
config:
"streams.sink.enabled": "true"
"streams.sink.topic.nodes": "graph-nodes"
"streams.sink.topic.relationships": "graph-relationships"
"kafka.bootstrap.servers": "kafka.analytics.svc.cluster.local:9092"
Troubleshooting¶
Common Issues and Solutions¶
Plugin Not Loading:
# Check plugin installation status
kubectl get neo4jplugin <plugin-name> -o yaml
# Verify Neo4j logs for plugin loading
kubectl logs <pod-name> -c neo4j | grep -i "plugin\|apoc\|gds"
# Check available procedures
kubectl exec <pod-name> -c neo4j -- \
cypher-shell -u neo4j -p password "SHOW PROCEDURES YIELD name WHERE name STARTS WITH 'apoc'"
Dependency Conflicts:
# Check for version mismatches
kubectl describe neo4jplugin <plugin-name>
# Common conflicts:
# - APOC version doesn't match Neo4j version
# - GDS requires specific APOC version
# - Multiple plugins trying to load same dependency
Resource Constraints:
# Check pod resource usage
kubectl top pod <pod-name> --containers
# Monitor during plugin installation
kubectl logs <pod-name> -c neo4j | grep -i "outofmemory\|heap"
# Common issues:
# - Insufficient memory for GDS operations
# - CPU limits too low for parallel plugin loading
License Issues (Commercial Plugins):
# Verify license secret exists
kubectl get secret <license-secret> -o yaml
# Check license file mounting
kubectl exec <pod-name> -c neo4j -- ls -la /licenses/
# Verify license in Neo4j
kubectl exec <pod-name> -c neo4j -- \
cypher-shell -u neo4j -p password "SHOW PROCEDURES YIELD name WHERE name CONTAINS 'bloom'"
Network and Source Issues:
# Test plugin source connectivity
kubectl run test-plugin --rm -it --image=curlimages/curl -- \
curl -I "https://repo1.maven.org/maven2/org/neo4j/procedure/apoc/"
# Check custom registry access
kubectl get secret <registry-auth-secret> -o yaml
Performance Monitoring¶
Note:
status.healthandstatus.usageare reserved and never populated today, so the commands below return nothing. Usekubectl get neo4jplugin <name> -o jsonpath='{.status.phase}'and the pod logs instead.
# Monitor plugin performance (reserved — empty today)
kubectl get neo4jplugin <plugin-name> -o jsonpath='{.status.health.performance}'
# Check plugin usage statistics
kubectl get neo4jplugin <plugin-name> -o jsonpath='{.status.usage.proceduresCalled}'
# View plugin health status
kubectl describe neo4jplugin <plugin-name> | grep -A 10 "Health:"
Best Practices¶
- Version Compatibility: Always match plugin versions with Neo4j version
- Dependency Management: Let the controller handle dependency resolution
- Resource Planning: Allocate sufficient memory for plugin operations (especially GDS)
- Security Configuration: Use appropriate procedure allowlists and security policies
- License Management: Store commercial plugin licenses in secure secrets
- Installation Order: Install base plugins (APOC) before dependent plugins (GDS)
- Monitoring: Regularly check the plugin
phaseand the Neo4j pod logs (thestatus.healthmetrics are reserved and not populated today) - Updates: Test plugin updates in development before production deployment
- Configuration: Use environment variables for APOC, neo4j.conf for other plugins
- Troubleshooting: Enable debug logging for plugin installation issues
For detailed plugin-specific guides, see: