Skip to main content
Tutorial 04 introduced the Pending<T> system with a database endpoint flowing into a Helm chart. The deploy block is where that pattern lives in practice — it’s the purpose-built ubx block for Helm releases, ArgoCD applications, and Flux kustomizations. Unlike a raw unit "kubernetes_helm_release" block, deploy "helm" is aware of the Pending type system from the ground up: every value in its values map can be a mix of resolved inputs and pending infrastructure outputs, and ubx generates exactly the right .apply() chains to sequence the Helm release after its dependencies. This tutorial focuses on the deploy "helm" block specifically — the chart name, version, namespace, and values — and shows how pending infrastructure outputs flow into Helm values cleanly.

What you’ll learn

  • The deploy "helm" block syntax — chart, version, namespace, values
  • How Pending<T> infrastructure outputs wire into Helm values automatically
  • How ubx sequences the Helm release after its infrastructure dependencies

Why this matters

deploy "helm" is the bridge between infrastructure provisioning and application deployment. Reference a resource output directly in the values map and the RDS endpoint becomes a database URL in a Helm values map — no CI glue, no manual copy-paste, no drift between what Terraform knows and what Helm uses.

The source code

# The RDS endpoint is Pending<string> — only known after the DB is created.
unit "aws_rds_instance" "db" {
  engine         = "postgres"
  instance_class = "db.t3.micro"
  identifier     = "myapp-${input.env}"
}

# deploy "helm" wires the pending endpoint into Helm values at apply time.
# ubx generates: db.endpoint.apply(endpoint => new helm.v3.Chart(...))
deploy "helm" "backend" {
  chart     = "my-backend"
  version   = "3.1.0"
  namespace = "backend"
  values = {
    db_host = unit.aws_rds_instance.db.endpoint  # Pending<string>
    db_port = 5432                                 # Resolved<int>
    env     = input.env                            # Resolved<string>
  }
}

How it works

1

deploy detects Pending values in its values map

During the IR pass, ubx scans the values map for pending resource references. db_host = unit.aws_rds_instance.db.endpoint is Pending<string>. The IR records this as a pending dependency on the RDS instance.
2

The emitter wraps the Chart in an .apply() chain

Because db_host is pending, the entire deploy "helm" "backend" block must wait for db.endpoint to resolve. The emitter generates db.endpoint.apply(endpoint => new helm.v3.Chart(...)), ensuring Pulumi sequences the Helm release after the RDS instance.
3

Resolved values are inlined directly

db_port = 5432 and env = input.env are both resolved — they’re inlined directly into the Chart constructor without any .apply() wrapping. Only the pending values drive the sequencing.

What ubx generates

// Generated by ubx — do not edit
import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as k8s from "@pulumi/kubernetes";

const config = new pulumi.Config();
const env = config.get("env") || "dev";

const db = new aws.rds.Instance("db", {
    engine: "postgres",
    instanceClass: "db.t3.micro",
    identifier: `myapp-${env}`,
});

// Sequenced after db.endpoint resolves
const backend = db.endpoint.apply(endpoint =>
    new k8s.helm.v3.Chart("backend", {
        chart: "my-backend",
        version: "3.1.0",
        namespace: "backend",
        values: {
            db_host: endpoint,   // from Pending<string>
            db_port: 5432,       // resolved
            env: env,            // resolved
        },
    })
);

export const dbEndpoint = db.endpoint;

Common mistakes

A deploy "helm" block without any pending resource references in its values map is not sequenced after any resource — it runs immediately in parallel with everything else. If your Helm chart depends on resources existing first (namespaces, CRDs, config maps), make sure at least one resource output reference or an explicit depends_on links it to those resources.
The version attribute pins the Helm chart version. Omitting it uses the latest version, which can cause unexpected updates when the chart is updated upstream. Always pin chart versions in production stacks.

Run it

ubx validate   # type-checks Pending<T> references
ubx plan       # requires AWS + Kubernetes credentials
ubx apply      # provisions RDS first, then deploys Helm chart

What you learned

deploy "helm" wires pending infrastructure outputs into Helm values automatically
ubx sequences the Helm release after its pending dependencies via .apply() chains
Resolved values are inlined directly — only pending values drive sequencing

Next steps

sync ArgoCD application

Register a GitOps application with ArgoCD

deploy block reference

Full deploy block syntax