Open-Source Wikis

/

Pulumi

/

Apps

/

The `pulumi` CLI

pulumi/pulumi

The pulumi CLI

Active contributors: Ian Wahbe, Justin Van Patten, Thomas Gummerer, Fraser Ashyggton

Purpose

The pulumi CLI is the single binary every Pulumi user runs. It parses command-line input, locates the user's project, instantiates a deployment engine, spawns language hosts and providers, and renders progress to the terminal. It is the most-touched and most-tested surface in the repo.

Directory layout

pkg/cmd/pulumi/
├── main.go                    # tiny entry point — calls NewPulumiCmd and runs
├── pulumi.go                  # the giant root command (≈33 KB) with every subcommand registration
├── pulumi_test.go             # full-CLI integration tests
├── about/                     # `pulumi about` (CLI + system info)
├── ai/                        # `pulumi ai` (AI integrations)
├── auth/                      # login / logout / token lifecycle
├── autonaming/                # `pulumi autonaming` (resource auto-naming controls)
├── cmd/                       # generic command helpers
├── config/                    # `pulumi config get/set/...`
├── convert/                   # `pulumi convert` (Terraform/CFN/etc → Pulumi)
├── deployment/                # `pulumi deployment` (cloud deployments)
├── env/                       # `pulumi env` (ESC environments)
├── events/                    # event filtering and streaming
├── install/                   # `pulumi install` (plugin install)
├── logs/                      # `pulumi logs`
├── neo/                       # next-gen command tree (under construction)
├── newcmd/                    # `pulumi new` (project bootstrap)
├── operations/                # programmatic operation runner — used by Automation API in-process
├── org/                       # org-scoped commands (cloud)
├── packagecmd/                # package-level commands
├── packageinstallation/       # plugin install machinery
├── packageresolution/         # plugin/version resolution logic
├── packageworkspace/          # workspace-scoped package management
├── plugin/                    # `pulumi plugin ls/install/...`
├── policy/                    # `pulumi policy` (policy packs)
├── project/                   # project-level helpers
├── schema/                    # schema commands (`pulumi schema check` etc.)
├── stack/                     # `pulumi stack`
├── state/                     # `pulumi state` (snapshot surgery)
├── templatecmd/               # `pulumi template`
├── trace/                     # `pulumi trace` (tracing decoder)
├── ui/                        # interactive UI components for prompts
├── version/                   # `pulumi version`
└── whoami/                    # `pulumi whoami`

How a command runs

graph TD
    main[pkg/cmd/pulumi/main.go] -->|NewPulumiCmd| Root[Root cobra.Command]
    Root -->|cobra subcommand routing| Sub[Subcommand handler<br/>e.g. pkg/cmd/pulumi/up]
    Sub -->|loads| Workspace[Workspace<br/>sdk/go/common/workspace]
    Sub -->|chooses| Backend[Backend<br/>diy or httpstate]
    Sub -->|configures| Engine[Engine<br/>pkg/engine]
    Engine -->|emits events| Display[Display<br/>pkg/cmd/pulumi/display + pkg/backend/display]
    Display -->|renders| Term[Terminal]

main.go is a few-line shim. The interesting code is in pulumi.go — the giant NewPulumiCmd() function builds the cobra command tree and wires every subcommand. Each subcommand package contributes a constructor (e.g. stack.NewStackCmd()) that returns a *cobra.Command.

Key abstractions

Symbol File Role
NewPulumiCmd pkg/cmd/pulumi/pulumi.go Constructs the root cobra command tree
Backend pkg/backend/backend.go Abstract over DIY vs httpstate
currentBackend(...) pkg/cmd/pulumi/backend/ Selects the backend for the current login
Workspace sdk/go/common/workspace/ The on-disk project + stack representation
Engine pkg/engine/engine.go What every operation eventually creates
displayEvents pkg/cmd/pulumi/display/ Renders engine events to terminal

CLI surface

The major user-visible commands. Each routes to a subpackage under pkg/cmd/pulumi/:

Command Subpackage Purpose
pulumi up (in pulumi.go) Apply desired state
pulumi preview (in pulumi.go) Plan only
pulumi destroy (in pulumi.go) Tear down
pulumi refresh (in pulumi.go) Reconcile state with cloud
pulumi import (in pulumi.go) Bring existing resources under management
pulumi new newcmd/ Scaffold from a template
pulumi convert convert/ TF/CFN/Kube → Pulumi
pulumi stack ... stack/ Stack lifecycle
pulumi config ... config/ Stack config
pulumi state ... state/ Snapshot surgery
pulumi plugin ... plugin/ Plugin cache management
pulumi package ... packagecmd/ Package commands
pulumi policy ... policy/ Policy packs
pulumi env ... env/ ESC environments
pulumi deployment ... deployment/ Cloud-managed deployments
pulumi about about/ Version + system info
pulumi login/logout auth/ Auth lifecycle
pulumi schema ... schema/ Schema utilities

How the CLI talks to the engine

The CLI does not hold the engine state in-process. For each operation:

  1. Resolve workspace and stack.
  2. Pull the latest snapshot from the chosen backend.
  3. Construct an engine.UpdateInfo (target stack + source program).
  4. Call engine.Update(...) (or Preview, Destroy, etc.).
  5. Stream the engine's events through the display layer to the terminal.
  6. Persist the resulting snapshot.

pkg/cmd/pulumi/operations/ exposes the same flow as a library, which is what Automation API runs.

Display

Engine events are rendered by pkg/backend/display/ (TUI/JSON renderer) plus terminal helpers in pkg/cmd/pulumi/display/. The display layer is event-driven — it never reaches into engine state directly. This isolation is what lets Pulumi Cloud reuse the same renderer to draw deployments in the browser.

Entry points for modification

  • Adding a new top-level subcommand — add a constructor in a new (or existing) subpackage, register it from pkg/cmd/pulumi/pulumi.go. Mirror an existing simple command (e.g. whoami) as a template.
  • Adding a flag to pulumi uppulumi.go again. Threads through to pkg/engine/update.go's Update() options.
  • Changing how snapshots load — go through the Backend interface in pkg/backend/backend.go; do not touch ~/.pulumi paths from the CLI.
  • Changing displaypkg/backend/display/ is the canonical renderer.

Tests

  • Smoke tests: tests/smoke/
  • Full integration: tests/integration/<name>/<lang>/
  • Per-command unit tests: pkg/cmd/pulumi/*_test.go
  • Login/auth-specific: tests/login/

See also

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

The `pulumi` CLI – Pulumi wiki | Factory