.iac file you write compiles to the same semantics regardless of which runtime you choose; only the generated language changes.
Choosing a runtime
Set theruntime key in ubx.yaml:
runtime is omitted, ubx defaults to typescript.
Generated files per runtime
| Runtime | Files generated | Pulumi.yaml runtime |
|---|---|---|
typescript | .ubx/index.ts, .ubx/package.json | nodejs |
python | .ubx/__main__.py, .ubx/requirements.txt | python |
go | .ubx/main.go, .ubx/go.mod | go |
.ubx/Pulumi.yaml with the correct runtime: field so Pulumi knows how to execute the stack.
TypeScript (default)
TypeScript is the default and most feature-complete target. It supports all ubx language features includingcomponent blocks with local .iac authoring, for_each, count, when, and all five secret() backends.
.ubx/index.ts:
Python
The Python target generates idiomatic Pulumi Python. Provider packages are imported aspulumi_aws, pulumi_gcp, pulumi_azure_native, etc.
.ubx/__main__.py:
.ubx/requirements.txt:
requirements.txt default to the latest major. Use a provider block to pin a specific version:
Go
The Go target generates a singlemain.go with a pulumi.Run() entry point and a go.mod for the provider dependencies.
.ubx/main.go:
.ubx/go.mod:
go.mod default to the latest major. Use a provider block to pin a specific version:
~> 6.2.1 → v6.2.1 in go.mod.
Pending<T> compilation per runtime
References to resource outputs (unit.name.attr, component.name.output, @stack.output) resolve at apply time and have type Pending<T>. Each runtime compiles them differently:
TypeScript
Single pending ref:Python
Single pending ref:Go
Single pending ref:Provider imports per runtime
| Provider | TypeScript import | Python import | Go import |
|---|---|---|---|
| AWS | import * as aws from "@pulumi/aws" | import pulumi_aws as aws | github.com/pulumi/pulumi-aws/sdk/v6/go/aws |
| GCP | import * as gcp from "@pulumi/gcp" | import pulumi_gcp as gcp | github.com/pulumi/pulumi-gcp/sdk/v7/go/gcp |
| Azure Native | import * as azure from "@pulumi/azure-native" | import pulumi_azure_native as azure | github.com/pulumi/pulumi-azure-native/sdk/v2/go/azure |
| Kubernetes | import * as k8s from "@pulumi/kubernetes" | import pulumi_kubernetes as k8s | github.com/pulumi/pulumi-kubernetes/sdk/v4/go/kubernetes |
| Datadog | import * as datadog from "@pulumi/datadog" | import pulumi_datadog as datadog | github.com/pulumi/pulumi-datadog/sdk/v4/go/datadog |
aws_s3_bucket_v2 the import is ...aws/s3 and the constructor is s3.NewBucketV2.
Sensitive outputs per runtime
Thesensitive = true field on an output block wraps the exported value in the runtime’s secret wrapper:
| Runtime | Generated code |
|---|---|
| TypeScript | pulumi.secret(value) |
| Python | pulumi.Output.secret(value) |
| Go | pulumi.ToSecret(value) |
Inputs per runtime
| ubx input | TypeScript | Python | Go |
|---|---|---|---|
| No default | new pulumi.Config().require("name") | config.require("name") | cfg.Require("name") |
| With default | ?? "default" | config.get("name") or "default" | cfg.Get("name") with fallback |
| Ephemeral | pulumi.secret(config.require("name")) | config.require_secret("name") | cfg.RequireSecret("name") |
Architecture note
All three runtimes share the same compilation pipeline up through the IR (Intermediate Representation) stage:Component Runtime Auto-Detection
When noruntime is declared in ubx.yaml or the ubx {} block, ubx inspects local component source directories and auto-detects the stack runtime. The first component with a recognisable entry-point file sets the runtime for the whole stack:
| Entry-point file | Detected runtime |
|---|---|
__main__.py | Python |
index.ts | TypeScript |
main.go | Go |
component blocks, or with only git:: sources, fall back to TypeScript when no runtime is set explicitly.
The stack-level runtime key is still supported and takes precedence over auto-detection — set it explicitly when you want to lock the runtime regardless of component contents:

