Deploy to Kubernetes

This page covers installing Enterprise Studio with Helm, configuring values, managing secrets, and setting up TLS.

Prerequisites

  • helm (v3.8+): Install Helm

  • kubectl: Install kubectl

  • Access to a Kubernetes enviroment (cloud, on-prem, or local with a LoadBalancer resource implementation).

Configure Helm

Add the Enterprise Studio Helm chart repository.

helm repo add \
  enterprise-studio https://dist.neo4j.org/enterprise-studio/helm

Update repository

helm repo update enterprise-studio

Check available versions of Enterprise Studio Helm charts

helm search repo enterprise-studio/ --versions

Export a values template to use as a starting point:

helm show values \
  enterprise-studio/neo4j-enterprise-studio \
  --version '<VERSION>' > values.yaml

Configure values

Edit values.yaml with your deployment settings. At a minimum, you need to configure:

  • Asset storage connection (URI, database name, credentials)

  • At least one Neo4j deployment for users to connect to

See Reference for the full list of available settings.

Minimal example

Replace <ASSET-STORAGE-HOST>, <DEPLOYMENT-HOST>, <NEO4J-SERVICE-ACCOUNT>, and <NEO4J-SERVICE-ACCOUNT-PASSWORD> with values from your environment, and provide your Enterprise Studio license.

secrets:
  licenseKey: |          (1)
    <contents of your nes.license file>
  assetStorageCredentials:
    username: "<NEO4J-SERVICE-ACCOUNT>"
    password: "<NEO4J-SERVICE-ACCOUNT-PASSWORD>"

assetStorage:
  uri: "neo4j://<ASSET-STORAGE-HOST>:7687"
  database: tools-storage

neo4jDeployments:                 (2)
  minexample:
    name: "Minimal Example"
    uri: "http://<DEPLOYMENT-HOST>:7474"
1 A valid license is required to start. The chart writes this into a Secret and mounts it at license.path (default /app/nes.license). To reference an existing Secret instead, use secretsFromSecrets.licenseKey.
2 neo4jDeployments is a map keyed by deployment id (letters and digits only). Each entry needs at least name and uri. See Configuration → Neo4j deployments for the full schema. <DEPLOYMENT-HOST> — hostname or IP of the Neo4j deployment Studio users connect to (HTTP port 7474).
  • <ASSET-STORAGE-HOST> — Hostname or IP of the Neo4j instance used for asset storage (Bolt port 7687).

  • <DEPLOYMENT-HOST> — Hostname or IP of the Neo4j deployment that Studio users connect to (HTTP port 7474).

  • <NEO4J-SERVICE-ACCOUNT> — Service account username for the asset storage connection.

  • <NEO4J-SERVICE-ACCOUNT-PASSWORD> — Password for the Neo4j service account used for the asset storage connection.

If a deployment uri points to a Neo4j cluster, the HTTP endpoint must provide session affinity, or transactions fail intermittently with Transaction with Id …​ was not found errors. See Prerequisites → Set up communication to a Neo4j cluster.

After you install with the example release name my-enterprise-studio, you can reach Enterprise Studio from your machine in a local setup (without a load balancer or ingress) by port-forwarding the HTTP service and opening the app in your browser:

kubectl port-forward svc/my-enterprise-studio-http 8080:80

Open http://localhost:8080 in your browser while the port-forward command is running.

Install

helm install my-enterprise-studio \
  enterprise-studio/neo4j-enterprise-studio \
  --version '<VERSION>' \
  --values values.yaml

Verify the release is running:

kubectl get pods -l app.kubernetes.io/instance=my-enterprise-studio

Ensure the service my-enterprise-studio-http on port 80 is reachable from outside the cluster.

Upgrade

To upgrade to a new version or apply configuration changes:

helm upgrade my-enterprise-studio \
  enterprise-studio/neo4j-enterprise-studio \
  --version '<VERSION>' \
  --values values.yaml

To roll back to the previous release:

helm rollback my-enterprise-studio

Uninstall

helm uninstall my-enterprise-studio

This removes all Kubernetes resources created by the chart. It does not delete the asset storage database or any data in Neo4j.

Managing secrets

For production, do not store credentials in values.yaml. Use a cloud Secrets Manager when available (see Cloud Secrets Managers); otherwise use pre-created Kubernetes Secrets via secretsFromSecrets.

Using external Secrets

Reference existing Secrets by name:

secretsFromSecrets:
  assetStorageCredentials: "nes-storage"  (1)
  tlsSecretName: "nes-tls"               (2)
1 Name of a kubernetes.io/basic-auth Secret containing username and password keys.
2 Name of a kubernetes.io/tls Secret (e.g. from cert-manager) containing tls.crt and tls.key.

Chart behavior with external Secrets

  • Asset storage: When secretsFromSecrets.assetStorageCredentials is set, the chart does not create its own credentials Secret; the Deployment references your Secret directly.

  • TLS: When secretsFromSecrets.tlsSecretName is set, the chart uses that existing TLS Secret for Ingress or in-pod HTTPS (depending on your TLS configuration). The inline secrets.ingressTlsCert/secrets.ingressTlsKey values are ignored.

Install-time alternatives

If Helm lookup is disabled in your environment, inject secrets at install time:

helm install my-enterprise-studio \
  enterprise-studio/neo4j-enterprise-studio \
  --version '<VERSION>' \
  --values values.yaml \
  --set secrets.assetStorageCredentials.password="$(kubectl get secret nes-storage -o jsonpath='{.data.password}' | base64 -d)" \
  --set-file secrets.ingressTlsCert=./certs/tls.crt \
  --set-file secrets.ingressTlsKey=./certs/tls.key

Cloud Secrets Managers

If Helm values use Secrets Manager references (usernameFrom, passwordFrom, or clientSecretFrom), give the pod cloud credentials through workload identity — do not put access keys in values or config.yaml. When passwordFrom or usernameFrom is set, the chart does not inject that field from a Kubernetes Secret; it only creates or references the ServiceAccount. Secret shape and required permissions are covered under Configuration → Secrets Manager. Wire identity into Helm via serviceAccount (and podLabels on AKS) as shown below.

Provider Recommended identity

AWS (EKS)

Azure (AKS)

Google Cloud (GKE)

AWS

Configure pod identity with IRSA (see also Assign IAM roles to Kubernetes service accounts). Ensure the role can read the secrets Enterprise Studio will resolve.

In Helm values, annotate the ServiceAccount, enable secretsManager.aws, and set usernameFrom / passwordFrom with secretRef type aws. For secret shape and permissions, see Configuration → AWS Secrets Manager.

Example values-aws.yaml
serviceAccount:
  create: true
  annotations:
    eks.amazonaws.com/role-arn: arn:aws:iam::ACCOUNT:role/nes-studio  (1)

secretsManager:
  aws:
    enabled: true
    region: eu-west-1

secrets:
  licenseKey: |
    <contents of your nes.license file>

assetStorage:
  uri: neo4j://my-neo4j-host:7687
  database: tools-storage
  authentication:
    basic:
      usernameFrom:
        secretRef:
          type: aws
          name: nes-assetstore-username  (2)
      passwordFrom:
        secretRef:
          type: aws
          name: nes-assetstore-password

neo4jDeployments:
  production:
    name: Production Graph
    uri: https://neo4j-prod:7473
1 IAM role ARN for this ServiceAccount. Set according to the IRSA documentation linked above.
2 Secrets Manager secret name or ARN. See Configuration → AWS Secrets Manager.

Azure

Configure pod identity with Microsoft Entra Workload ID (see also Deploy and configure workload identity on an AKS cluster). Ensure the identity can read the secrets Enterprise Studio will resolve.

In Helm values, set the ServiceAccount annotation and podLabels, enable secretsManager.azure, and set usernameFrom / passwordFrom with secretRef type azure. For secret shape and permissions, see Configuration → Azure Key Vault.

Example values-azure.yaml
serviceAccount:
  create: true
  annotations:
    azure.workload.identity/client-id: <CLIENT_ID>  (1)

podLabels:
  azure.workload.identity/use: "true"  (2)

secretsManager:
  azure:
    enabled: true
    vaultUrl: https://contoso.vault.azure.net/

secrets:
  licenseKey: |
    <contents of your nes.license file>

assetStorage:
  uri: neo4j://my-neo4j-host:7687
  database: tools-storage
  authentication:
    basic:
      usernameFrom:
        secretRef:
          type: azure
          name: nes-assetstore-username  (3)
      passwordFrom:
        secretRef:
          type: azure
          name: nes-assetstore-password

neo4jDeployments:
  production:
    name: Production Graph
    uri: https://neo4j-prod:7473
1 Managed identity client ID for this ServiceAccount. Set according to the Workload ID documentation linked above.
2 Required for Microsoft Entra Workload ID on the pod. See the Workload ID documentation linked above.
3 Key Vault secret name. See Configuration → Azure Key Vault.

Google Cloud

Configure pod identity with Workload Identity Federation for GKE (see also Authenticate to Google Cloud APIs from GKE workloads). Ensure the identity can read the secrets Enterprise Studio will resolve.

In Helm values, annotate the ServiceAccount, enable secretsManager.gcp, and set usernameFrom / passwordFrom with secretRef type gcp. For secret shape and permissions, see Configuration → Google Cloud Secret Manager.

Example values-gcp.yaml
serviceAccount:
  create: true
  annotations:
    iam.gke.io/gcp-service-account: [email protected]  (1)

secretsManager:
  gcp:
    enabled: true
    project: my-project

secrets:
  licenseKey: |
    <contents of your nes.license file>

assetStorage:
  uri: neo4j://my-neo4j-host:7687
  database: tools-storage
  authentication:
    basic:
      usernameFrom:
        secretRef:
          type: gcp
          name: nes-assetstore-username  (2)
      passwordFrom:
        secretRef:
          type: gcp
          name: nes-assetstore-password

neo4jDeployments:
  production:
    name: Production Graph
    uri: https://neo4j-prod:7473
1 Google service account email for this ServiceAccount. Set according to the Workload Identity documentation linked above.
2 Secret Manager secret ID. See Configuration → Google Cloud Secret Manager.

Ingress and inbound TLS

Enterprise Studio supports two inbound TLS termination models (browser → Enterprise Studio):

  • Ingress-terminated TLS: the Ingress controller handles TLS; the pod serves plain HTTP.

  • In-pod TLS (SSL passthrough): the pod terminates TLS; the Ingress just forwards encrypted traffic.

These configure Enterprise Studio as an HTTPS server only (server.https.enabled, server.https.certificates.*). They do not affect outbound trust when Enterprise Studio calls Neo4j. See Outbound TLS trust (private CAs) for private CA trust to Neo4j backends.

Ingress-terminated TLS

The Ingress controller handles TLS decryption. The pod serves HTTP on server.port (default 8080). Set ingress.httpHostName to the hostname clients use to reach Enterprise Studio.

ingress:
  enabled: true
  sslPassthrough: false
  ingressClassName: nginx
  httpHostName: studio.example.com
  annotations: {}

server:
  https:
    enabled: false

# Provide cert inline or via secretsFromSecrets
secrets:
  ingressTlsCert: '<PEM certificate>'
  ingressTlsKey: '<PEM private key>'

For cert-manager, set secretsFromSecrets.ingressTlsCert.secretName to your kubernetes.io/tls Secret instead of inline PEM strings.

Use ingress.annotations to customize the Ingress controller (for example, nginx-specific settings like proxy timeouts or body size limits).

In-pod TLS (SSL passthrough)

The pod terminates TLS directly. Use this with a LoadBalancer Service, port-forwarding, or an Ingress with SSL passthrough.

server:
  https:
    enabled: true
    certificates:
      baseDirectory: certificates/https
      privateKey: private.key
      publicCertificate: public.crt

ingress:
  enabled: true
  sslPassthrough: true
  ingressClassName: nginx
  httpHostName: studio.example.com

secrets:
  httpsTlsCert: '<PEM certificate>'
  httpsTlsKey: '<unencrypted PKCS#8 private key>'

The nginx Ingress controller requires SSL passthrough to be enabled on the controller (e.g. controller.extraArgs.enable-ssl-passthrough).

In-pod TLS without Ingress (LoadBalancer)

If you do not need Ingress and want to expose Enterprise Studio directly via a LoadBalancer:

server:
  https:
    enabled: true
    certificates:
      baseDirectory: certificates/https
      privateKey: private.key
      publicCertificate: public.crt

secrets:
  httpsTlsCert: '<PEM certificate>'
  httpsTlsKey: '<unencrypted PKCS#8 private key>'

ingress:
  enabled: false

service:
  http:
    type: LoadBalancer

The chart mounts the certificate and key at /app/certificates/https as public.crt and private.key.

For certificate format and key requirements, see Security → TLS encryption.

Outbound TLS trust (private CAs)

When Enterprise Studio connects to Neo4j over HTTPS or Bolt+TLS, it uses the system trust store inside the pod (/etc/ssl/certs). There is no Enterprise Studio configuration setting for outbound TLS trust — install upstream CAs in the pod where Enterprise Studio runs. Host OS trust does not apply inside Kubernetes pods.

Use this when:

  • deployments.*.uri uses https:// with a private or self-signed CA

  • assetStorage.uri uses neo4j+s:// with a private CA

Outbound pod trust is independent of inbound TLS. If TLS terminates at Ingress and Enterprise Studio serves HTTP in-pod, outbound trust is still required for HTTPS Neo4j backends and neo4j+s:// asset storage.

The Helm chart (0.2.1 and later) mounts a trusted upstream CA at /etc/ssl/certs/ca.crt in the Enterprise Studio pod when either value below is set.

Helm value Description

secrets.trustedCaCert

PEM-encoded upstream CA; the chart creates an Opaque Secret and mounts it in the pod

secretsFromSecrets.trustedCaCert

Reference an existing Secret (secretName and key; default key ca.crt)

Inline CA at install time

Pass the CA file when installing or upgrading:

helm upgrade --install my-enterprise-studio \
  enterprise-studio/neo4j-enterprise-studio \
  --version '<VERSION>' \
  --values values.yaml \
  --set-file secrets.trustedCaCert=./ca.crt

Or embed the PEM in values.yaml:

secrets:
  trustedCaCert: |
    -----BEGIN CERTIFICATE-----
    ...
    -----END CERTIFICATE-----

Reference an existing Secret

For production, create the CA Secret separately and reference it by name:

secretsFromSecrets:
  trustedCaCert:
    secretName: neo4j-ca
    key: ca.crt

See Security → TLS encryption for the trust model. See Docker deployment for the equivalent procedure with docker run.

Setting up a new Neo4j instance for asset storage

If you don’t have an existing Neo4j instance for asset storage, you can deploy one alongside Enterprise Studio:

helm install nes-asset-storage neo4j/neo4j \
  --set neo4j.name=nes-asset-storage \
  --set neo4j.password=changeme \
  --set neo4j.edition=enterprise \
  --set neo4j.acceptLicenseAgreement=yes \
  --set volumes.data.mode=defaultStorageClass

Find the cluster IP:

kubectl get svc nes-asset-storage

Then use that IP in your values.yaml:

assetStorage:
  uri: "neo4j://<CLUSTER-IP>:7687"
  database: tools-storage

Health probes

Enterprise Studio exposes a GET /health endpoint that returns 200 OK when the server is running. It does not verify backend connectivity (for example to the asset storage database).

Running multiple replicas

Enterprise Studio is stateless (see Architecture → Scalability and high availability). The Helm chart supports configuring horizontal pod autoscaling. The default values are:

hpa:
  spec:
    targetCPUUtilizationPercentage: 70
    maxReplicas: 2

Override these values in your values.yaml if needed.

When a deployment proxies queries to a Neo4j cluster, session affinity must be configured in front of the cluster regardless of the number of Enterprise Studio replicas. See Prerequisites → Set up communication to a Neo4j cluster.