> This page is for Boltz-2, version 1.8.0.
> For other versions, use one of these documentation indexes:
> - 1.10.0 (Latest) (default): https://docs.nvidia.com/nim/bionemo/boltz2/1.10.0/llms.txt
> - 1.9.0: https://docs.nvidia.com/nim/bionemo/boltz2/1.9.0/llms.txt
> - 1.8.0: https://docs.nvidia.com/nim/bionemo/boltz2/1.8.0/llms.txt
> - 1.7.0: https://docs.nvidia.com/nim/bionemo/boltz2/1.7.0/llms.txt
> - 1.6.0: https://docs.nvidia.com/nim/bionemo/boltz2/1.6.0/llms.txt
> - 1.5.0: https://docs.nvidia.com/nim/bionemo/boltz2/1.5.0/llms.txt
> - 1.4.0: https://docs.nvidia.com/nim/bionemo/boltz2/1.4.0/llms.txt
> - 1.3.0: https://docs.nvidia.com/nim/bionemo/boltz2/1.3.0/llms.txt
> - 1.2.0: https://docs.nvidia.com/nim/bionemo/boltz2/1.2.0/llms.txt
> - 1.1.0: https://docs.nvidia.com/nim/bionemo/boltz2/1.1.0/llms.txt
> - 1.0.0: https://docs.nvidia.com/nim/bionemo/boltz2/1.0.0/llms.txt

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

# Deploy Boltz2 with Helm

Boltz2 NIMs are designed to run on systems with NVIDIA GPUs. To deploy using Helm, you must have a Kubernetes cluster with appropriate GPU nodes and the GPU Operator installed.

## Prerequisites

If you have not set up your NGC API key, refer to [Getting Started](/nim/bionemo/boltz2/1.8.0/getting-started) first.

### Required Components

- Configured Kubernetes cluster with GPU nodes
- [NVIDIA GPU Operator](https://docs.nvidia.com/datacenter/cloud-native/gpu-operator/latest/index.html) installed
- [Helm](https://helm.sh/docs/intro/install/) 3.x or later
- [kubectl](https://kubernetes.io/docs/tasks/tools/) configured to access your cluster
- NGC API key with access to Boltz2 NIM

### Download the Helm Chart

The Boltz2 NIM Helm chart is available from the NGC Catalog. Use the following command to download the chart:

```bash
helm pull https://helm.ngc.nvidia.com/nim/mit/charts/boltz2-nim-<version>.tgz --username='$oauthtoken' --password=<YOUR API KEY>
```
Replace `<version>` with the desired chart version. In most cases, you should use the latest version available at:
[https://catalog.ngc.nvidia.com/orgs/nim/teams/mit/helm-charts/boltz2-nim/files](https://catalog.ngc.nvidia.com/orgs/nim/teams/mit/helm-charts/boltz2-nim/files)

## Configure Helm

The following Helm options are the most important to configure for deploying Boltz2 NIM:

### Core Configuration Options

- **`boltz2.repository`** – The Boltz2 NIM container to deploy
- **`boltz2.tag`** – The version of the container
- **`boltz2.servicePort`** – The port the Kubernetes service listens on (default: `8081`)
- **Storage options** – Based on your cluster environment (see [Storage](#storage) section)
- **`imagePullSecret`** – For NGC authentication:
    - `name` is used as the pod's image pull secret.
    - `secretName` and `secretKey` supply the NGC API key to the container (for example, `NGC_API_KEY`). You can use one secret for both, or separate secrets for image pull and the API key.

- **`resources`** – GPU and memory requirements

To view all available configuration options, run:

```bash
helm show readme boltz2-nim-<version>.tgz | less
```

To examine default values:

```bash
helm show values boltz2-nim-<version>.tgz
```

## Quick Start Deployment

### 1. Create NGC Secrets

Create the necessary Kubernetes secrets for NGC authentication. The chart uses a single **`imagePullSecret`** object. Its `name` is the secret used for pulling the image. `secretName` and `secretKey` identify the secret and key used to set the NGC API key in the container (for example, `NGC_API_KEY`). You can use one secret for both roles or separate secrets.

```bash
# Image pull secret (referenced by imagePullSecret.name)
kubectl create secret docker-registry ngc-secret \
  --docker-server=nvcr.io \
  --docker-username='$oauthtoken' \
  --docker-password=$NGC_API_KEY

# NGC API key secret (referenced by imagePullSecret.secretName / secretKey)
kubectl create secret generic ngc-api \
  --from-literal=NGC_API_KEY=$NGC_API_KEY
```

### 2. Create Values File

Create a file named `custom-values.yaml` with your configuration. Use **`imagePullSecret`** (not `ngc.apiSecret` or `imagePullSecrets`). Set `name` to the image pull secret name and `secretName`/`secretKey` to the secret and key that hold the NGC API key for the container.

```yaml
boltz2:
  repository: "nvcr.io/nim/mit/boltz2"
  tag: "1.8.0"

# Chart uses imagePullSecret; ngc.apiSecret and imagePullSecrets are not supported.
imagePullSecret:
  name: ngc-secret              # Pod imagePullSecrets use this name
  secretName: ngc-api           # Secret used for NGC_API_KEY in the container
  secretKey: NGC_API_KEY        # Key name in that secret

persistence:
  enabled: true
  size: 100Gi

resources:
  limits:
    nvidia.com/gpu: 1
    memory: 64Gi
  requests:
    memory: 32Gi
```

### 3. Install the Chart

Deploy Boltz2 NIM using Helm:

```bash
export CHART_NAME=boltz2-nim
helm install "${CHART_NAME}" boltz2-nim-<version>.tgz -f custom-values.yaml
```

### 4. Verify Deployment

Check the pod status:

```bash
kubectl get pods
```

View logs to monitor startup progress:

```bash
kubectl logs -f <pod-name>
```

<Note>
Due to large model files, pods may take several minutes to start. The NIM will download model weights on first startup if they are not already present in the persistent volume.
</Note>

## Storage

Proper storage configuration is critical for Boltz2 NIM deployment. The model cache can be large, and you have several options:

### Persistent Volume Claims (Recommended)

Enabled with `persistence.enabled: true`. The chart supports the following persistence options:

| Field | Default | Description |
|-------|---------|--------------|
| `enabled` | `true` | Enable persistent storage for the model cache |
| `existingClaim` | `""` | Use an existing PVC by name; if set, no new PVC is created |
| `storageClass` | `standard` | StorageClass for dynamic provisioning; use `""` for cluster default |
| `accessMode` | `ReadWriteOnce` | Access mode for the volume |
| `hostPath` | `/data/nim` | Host path when using hostPath (development) |
| `size` | `10Gi` | Size of the volume; increase for large model caches |
| `fixPermissions` | `true` | Adjust volume permissions on startup |

Example using chart defaults:

```yaml
persistence:
  enabled: true
  existingClaim: ""
  storageClass: standard
  accessMode: ReadWriteOnce
  hostPath: /data/nim
  size: 10Gi
  fixPermissions: true
```

To use the cluster default StorageClass, set `storageClass: ""`. For production with a large model cache, increase `size` (e.g. `100Gi`):

```yaml
persistence:
  enabled: true
  storageClass: ""  # Use default storage class
  size: 100Gi
```

For multi-pod scenarios, use a storage class that supports `ReadWriteMany`:

```yaml
persistence:
  enabled: true
  storageClass: "nfs-client"  # Example: NFS storage class
  accessMode: ReadWriteMany
  size: 100Gi
```

### Alternative Storage Options

#### NFS Storage

The chart does not support direct NFS volume mounts. For NFS-backed storage, use a StorageClass that provisions NFS volumes and enable persistence:

```yaml
persistence:
  enabled: true
  storageClass: "nfs-client"  # Or your cluster's NFS provisioner
  accessMode: ReadWriteMany
  size: 100Gi
```

#### HostPath (development)

The chart's PV template uses `persistence.hostPath` as the node path for the PersistentVolume (default: `/data/nim`). To use a different path on the node:

```yaml
persistence:
  enabled: true
  hostPath: /data/nim   # or e.g. /model-store — must exist on the node
  storageClass: standard
  size: 10Gi
```

<Warning>
HostPath ties the volume to a specific node and has security implications. Prefer a StorageClass for multi-node or production use.
</Warning>

## GPU Configuration

### Single GPU Deployment

Most Boltz2 deployments use a single GPU:

```yaml
resources:
  limits:
    nvidia.com/gpu: 1
```

### GPU Selection

Use node selectors to target specific GPU types:

```yaml
nodeSelector:
  nvidia.com/gpu.product: "NVIDIA-H100-80GB-HBM3"
```

Or use tolerations for GPU taints:

```yaml
tolerations:
  - key: nvidia.com/gpu
    operator: Exists
    effect: NoSchedule
```

## Service Configuration

### Basic Service

The default service configuration exposes the Boltz2 API. The chart provides:

- **`service.type`** – Service type (default: `ClusterIP`). This is the only option under the `service` key.
- **`boltz2.servicePort`** – The port the service listens on (default: `8081`). To use a different port, set this under the `boltz2` section of your values.
- **Service name** – Generated from the Helm release name by the chart's templates and cannot be overridden.

Example values to change the service port:

```yaml
service:
  type: ClusterIP

boltz2:
  servicePort: 9090  # Default is 8081
```

### Port Forwarding (Testing)

For local testing, use port forwarding. Use the same port as `boltz2.servicePort` (default 8081) on the right side of the mapping:

```bash
kubectl port-forward service/"${CHART_NAME}" 8080:8081
```

If you set `boltz2.servicePort` to a different value (e.g. 9090), use that port instead:

```bash
kubectl port-forward service/"${CHART_NAME}" 8080:9090
```

Test the API:

```bash
curl http://localhost:8080/v1/health/live
```

### Ingress Configuration

For production deployments, configure ingress:

```yaml
ingress:
  enabled: true
  className: nginx
  annotations:
    cert-manager.io/cluster-issuer: letsencrypt-prod
  hosts:
    - host: boltz2.example.com
      paths:
        - path: /
          pathType: Prefix
  tls:
    - secretName: boltz2-tls
      hosts:
        - boltz2.example.com
```

## Advanced Configuration

### Autoscaling

The chart supports horizontal pod autoscaling based on CPU utilization (GPU-based autoscaling is not supported):

```yaml
autoscaling:
  enabled: true
  minReplicas: 1
  maxReplicas: 100
  targetCPUUtilizationPercentage: 80
```

If your chart version supports it, you can also set `targetMemoryUtilizationPercentage` for memory-based scaling.

### Custom Probes

The chart configures liveness and readiness probes under `probes.liveness` and `probes.readiness`. Probe paths are fixed in the template (`/v1/health/live` and `/v1/health/ready`). There is no `startupProbe` or `enabled`/`path` fields. Adjust timings for large models or slow storage:

```yaml
probes:
  liveness:
    initialDelaySeconds: 300
    periodSeconds: 10
    timeoutSeconds: 1
    successThreshold: 1
    failureThreshold: 3
  readiness:
    initialDelaySeconds: 300
    periodSeconds: 10
    timeoutSeconds: 1
    successThreshold: 1
    failureThreshold: 3
```

Increase `initialDelaySeconds` or `failureThreshold` if pods need more time to become ready.

### Security Context

Configure pod and container security (chart defaults):

```yaml
podSecurityContext:
  runAsUser: 1000
  runAsGroup: 1000
  fsGroup: 1000

securityContext:
  runAsUser: 1000
  runAsGroup: 1000
  allowPrivilegeEscalation: false
```

The chart uses `securityContext` for the container; there is no `containerSecurityContext` or `capabilities` in the default values.

## Run Inference

Once deployed, you can run predictions using the API.

<Note>
The host URL `http://localhost:8080` below only works after you forward the Kubernetes service to your machine. Run **`kubectl port-forward`** first (see [Port forwarding (Testing)](#port-forwarding-testing)), mapping a local port (here **8080**) to **`boltz2.servicePort`** on the service (default **8081**), for example: `kubectl port-forward service/"${CHART_NAME}" 8080:8081`.
</Note>

```bash
curl -X POST http://localhost:8080/biology/mit/boltz2/predict \
  -H "Content-Type: application/json" \
  -d '{
    "polymers": [
      {
        "molecule_type": "protein",
        "sequence": "MKTAYIAKQRQISFVKSHFSRQLEERLGLIEVQAPILSRVGDGTQDNLSGAEKAVQVKVKALPDAQFEVVHSLAKWKRQTLGQHDFSAGEGLYTHMKALRPDEDRLSPLHSVYVDQWDWERVMGDGERQFSTLKSTVEAIWAGIKATEAAVSEEFGLAPFLPDQIHFVHSQELLSRYPDLDAKGRERAIAKDLGAVFLVGIGGKLSDGHRHDVRAPDYDDWSTPSELGHAGLNGDILVWNPVLEDAFELSSMGIRVDADTLKHQLALTGDEDRLELEWHQALLRGEMPQTIGGGIGQSRLTMLLLQLPHIGQVQAGVWPAAVRESVPSLL"
      }
    ],
    "diffusion_samples": 1,
    "recycling_steps": 3
  }'
```

For detailed API documentation, refer to [Inference](/nim/bionemo/boltz2/1.8.0/inference).

## Troubleshooting

### Pod Stuck in Pending

Check events:

```bash
kubectl describe pod <pod-name>
```

Common issues:
- Insufficient GPU resources
- Node taints requiring tolerations
- Storage mount failures
- Image pull errors

### Pod Fails to Start

View logs:

```bash
kubectl logs <pod-name>
```

If the pod needs more time to become ready, increase probe delays or failure thresholds under `probes` (the chart does not support a startup probe):

```yaml
probes:
  liveness:
    initialDelaySeconds: 600  # Allow more time before first check
    failureThreshold: 10
  readiness:
    initialDelaySeconds: 600
    failureThreshold: 10
```

### Storage Issues

Verify PVC status:

```bash
kubectl get pvc
kubectl describe pvc <pvc-name>
```

Ensure storage class supports the required access mode.

### GPU Access

Test GPU availability:

```bash
kubectl run gpu-test \
  --image=nvidia/cuda:12.6.2-base-ubuntu22.04 \
  --restart=Never \
  --command -- nvidia-smi
```

## Uninstall

To remove the Boltz2 NIM deployment:

```bash
helm uninstall "${CHART_NAME}"
```

To also remove persistent volumes:

```bash
kubectl delete pvc -l app.kubernetes.io/instance="${CHART_NAME}"
```

## Additional Resources

- [Boltz2 Overview](/nim/bionemo/boltz2/1.8.0/overview)
- [Getting Started](/nim/bionemo/boltz2/1.8.0/getting-started)
- [Configure Boltz2](/nim/bionemo/boltz2/1.8.0/configure)
- [Inference API Reference](/nim/bionemo/boltz2/1.8.0/inference)
- [Performance Benchmarks](/nim/bionemo/boltz2/1.8.0/performance)
- [NGC Helm Chart Registry](https://catalog.ngc.nvidia.com/orgs/nim/teams/mit/helm-charts/boltz2-nim/files)