> This page is for version 0.7.
> For other versions, use one of these documentation indexes:
> - Latest (default): https://docs.nvidia.com/nemo-helix/latest/llms.txt
> - 0.9: https://docs.nvidia.com/nemo-helix/v0.9/llms.txt
> - 0.8: https://docs.nvidia.com/nemo-helix/v0.8/llms.txt
> - 0.7: https://docs.nvidia.com/nemo-helix/v0.7/llms.txt
> - 0.6: https://docs.nvidia.com/nemo-helix/v0.6/llms.txt
> - 0.5: https://docs.nvidia.com/nemo-helix/v0.5/llms.txt

> For clean Markdown of any page, append .md to the page URL.
> For a complete documentation index, see https://docs.nvidia.com/nemo-helix/llms.txt.
> For AI client integration (Claude Code, Cursor, etc.), connect to the MCP server at https://docs.nvidia.com/nemo-helix/_mcp/server.

# Database Setup

The NeMo Helix uses a SQL-based database to store entities such as workspaces, jobs, and other records.

By default, the NeMo Helix Helm chart deploys an embedded PostgreSQL instance (a StatefulSet using the official Postgres image) with simplified authentication to enable quick installation. This should not be used for production use, and an external PostgreSQL instance is recommended.

## Preserve embedded PostgreSQL claim-template labels on upgrade

Starting with chart v0.7.3, `postgresql.persistence.claimTemplateLabels` lets
existing installations retain the labels on the embedded PostgreSQL
StatefulSet's `data` volume claim template. Kubernetes treats this template as
immutable, so changing its labels during a Helm upgrade can cause the upgrade
to fail.

Before upgrading an older installation, inspect the existing StatefulSet:

```bash
kubectl get statefulset <postgres-statefulset> --namespace <namespace> -o yaml
```

Copy the complete label map from the `data` entry under
`spec.volumeClaimTemplates[].metadata.labels` into
`postgresql.persistence.claimTemplateLabels` in your Helm values. Copy the
claim-template labels, not the StatefulSet or Pod labels. Retain those exact
values on every future upgrade, including any old chart or application version
labels; do not replace them with the new release version. Supplied labels
override the default `app.kubernetes.io/component: postgres` label.

The default `{}` keeps the existing chart behavior for fresh installations.
This setting addresses claim-template labels only. Preserve your existing
release name, resource names, storage configuration, and secrets encryption key
and its Secret reference as well. External PostgreSQL installations are not
affected by this embedded-storage setting.

## External PostgreSQL Database

To use an external PostgreSQL database in the Helm chart:

1. Set `postgresql.enabled: false` and configure `externalDatabase`.
2. Choose one of the following approaches to create a Kubernetes secret with your credentials:

### Option 1: Use a full connection URI

Use a secret that holds the full database connection URI and reference it with `uriSecret`. This is the best option when you need to configure [TLS/SSL](https://www.postgresql.org/docs/current/libpq-ssl.html) or want a single secret for the connection string.

1. **Create a secret** containing the connection URI (optionally with SSL parameters):

```sh
kubectl create secret generic my-db-uri-secret --from-literal=uri='postgresql://nemo@db-host:5432/nemohelix'
```

For SSL, include `sslmode` in the URI:

```sh
kubectl create secret generic my-db-uri-secret --from-literal=uri='postgresql://nemo@db-host:5432/nemohelix?sslmode=require'
```

2. **Configure the chart** to use that secret:

```yaml
postgresql:
  enabled: false
externalDatabase:
  uriSecret:
    name: my-db-uri-secret
    key: uri
```

When `uriSecret` is set, the platform uses the URI from the secret and ignores `host`, `port`, `user`, `database`, and `existingSecret`.

### Option 2: Configure individual connection details

Use individual `host`, `port`, `user`, and `database` values and a secret that contains only the password. The platform builds the connection from these values.

1. **Create a secret** containing the password (the key must be `password`, or set `existingSecretPasswordKey` to the key name in your secret):

```sh
kubectl create secret generic my-db-password-secret --from-literal=password='my-password'
```

Or define the secret in YAML:

```yaml
apiVersion: v1
kind: Secret
metadata:
  name: my-db-password-secret
type: Opaque
stringData:
  password: my-password
```

2. **Configure the chart** with connection details and the secret name:

```yaml
postgresql:
  enabled: false
externalDatabase:
  host: db-host.example.com
  port: 5432
  user: nemo
  database: nemohelix
  existingSecret: my-db-password-secret
  existingSecretPasswordKey: "password" # key in the secret that holds the password
```