Skip to content

Pulumi — Theory

Pulumi runs your program once to construct a resource graph. The runtime then computes diff and applies.

  • Imperative-looking code → declarative model.
  • Same provider semantics as Terraform (most providers wrap Terraform’s).
  • Resources have inputs (you provide), outputs (cloud assigns).

Outputs are async because they depend on cloud responses (e.g., a generated ID, an ARN).

  • Input<T> accepts T | Promise<T> | Output<T>.
  • Output<T> is “computed value, possibly with secrets/dependencies tracked”.
  • pulumi.all([a, b]).apply(([av, bv]) => ...) to combine multiple Outputs.

If you do bucket.arn + "/key" you get junk because arn is an Output. Use interpolate or apply.

Wrap many primitives as one logical unit. They:

  • Show up as one entry in pulumi up summary.
  • Group lifecycle.
  • Are composable (a Component can contain Components).

Encourages reusable infra abstractions (“I have a WebService component that handles ALB+ECS+CloudWatch — drop it in any project”).

  • State stored as JSON in chosen backend.
  • Has resource graph + last-known inputs/outputs.
  • Encrypts secrets automatically using stack passphrase or KMS.
  • Stack state operations: pulumi state delete, pulumi state rename.
  • pulumi import to bring existing resources under management.
  • pulumi refresh updates state to match real world (similar to TF).
  • Detect drift by preview --diff after refresh.
  • pulumi config set --secret password xxx — encrypted in state.
  • Use pulumi.secret(value) to wrap any Output as secret.
  • KMS provider: pass --secrets-provider on stack init for cloud-key encryption.
const networkStack = new pulumi.StackReference("acme/network/prod");
const vpcId = networkStack.requireOutput("vpcId");

Equivalent to TF’s terraform_remote_state.

  1. Outputs are async — how do you build a string from one? pulumi.interpolate or .apply().
  2. What happens when your program errors mid-up? Pulumi rolls forward what succeeded; failed resource left in error state. Re-run resumes.
  3. TF vs Pulumi tradeoff? HCL discipline vs general-language flexibility.
  4. Where does state live? Pulumi Cloud or self-hosted (S3/GCS/Azure).
  5. How would you test infra? Mocks for unit tests; ephemeral stack + assert via SDK for integration.
  6. Migrate TF → Pulumi? Use pulumi import per resource, or tf2pulumi (legacy). Most do gradual stack-by-stack.
  • Treating Outputs as plain values.
  • Pulumi program with side effects (HTTP, file IO) at top level — runs every preview.
  • Not encrypting state at rest.
  • Mixing config and code (use Config namespace).
  • Letting program get too complex — refactor into Components.
  • Project structure: separate stacks for dev/staging/prod; same code, different config.
  • Components in lib/ for reuse across services.
  • CI runs pulumi preview on PR (with pulumi/actions GitHub Action), up on merge.
  • OIDC for cloud auth (no static keys in CI).
  • Pin SDK + provider versions.