pulumi/pulumi
Architecture
Pulumi is a multi-process, gRPC-driven system. A single pulumi up invocation spawns the CLI, an engine, a language host, and one or more provider plugins, and they communicate exclusively through Protobuf-defined RPCs. This page traces those processes and explains where each one lives in the repo.
The four roles
graph TD
User[Developer] -->|invokes| CLI[pulumi CLI<br/>pkg/cmd/pulumi]
CLI -->|creates| Engine[Deployment engine<br/>pkg/engine, pkg/resource/deploy]
Engine -->|spawns + RPCs| LangHost[Language host<br/>sdk/<lang>/cmd/pulumi-language-<lang>]
Engine -->|spawns + RPCs| Provider[Provider plugins<br/>e.g. pulumi-resource-aws]
LangHost -->|runs| UserProg[User program<br/>links against sdk/<lang>]
UserProg -->|RegisterResource etc.<br/>via ResourceMonitor| Engine
Engine -->|persists snapshot| Backend[Storage backend<br/>pkg/backend/diy or httpstate]Every Pulumi operation conforms to this shape. The arrows are gRPC connections defined in proto/pulumi/*.proto.
Components in this repo
pulumi CLI — pkg/cmd/pulumi/
The CLI is the only binary a user runs directly. Its entry point is pkg/cmd/pulumi/main.go, which calls into pkg/cmd/pulumi/pulumi.go (the giant NewPulumiCmd() function — ~33 KB) to register every subcommand. Subcommand groups live in their own subpackages: pkg/cmd/pulumi/stack, pkg/cmd/pulumi/config, pkg/cmd/pulumi/policy, pkg/cmd/pulumi/state, pkg/cmd/pulumi/plugin, etc. The CLI uses Cobra for command parsing.
For a deep-dive see apps/cli.
Deployment engine — pkg/engine/ and pkg/resource/deploy/
The engine is what the CLI spins up to actually do anything. It plans, executes, and records the side-effects of every operation. Two complementary subsystems:
pkg/engine/— operation entry points (update.go,destroy.go,refresh.go,import.go), event emission (events.go), plugin and policy management, and the journaled-snapshot infrastructure (journal_snapshot.go).pkg/resource/deploy/— the actual deployment: source iterators (source_eval.gois the largest file in the codebase at ~123 KB), the step generator (step_generator.go, ~137 KB), the step executor (step_executor.go), and the resource graph (snapshot.go).
The lifecycle test infrastructure under pkg/engine/lifecycletest/ is a fuzzing harness that exercises the engine through synthetic programs.
For details see systems/engine and primitives/resources-and-urns.
Language hosts — sdk/<lang>/cmd/pulumi-language-<lang>/
Each language Pulumi supports ships with a host — a Go process that wraps the language runtime in a gRPC interface defined in proto/pulumi/language.proto. The engine spawns a host, asks it to run the user's program, and the host streams ResourceMonitor calls back to the engine.
The hosts in this repo:
sdk/nodejs/cmd/pulumi-language-nodejs/— boots Node.js and runsindex.jssdk/python/cmd/pulumi-language-python/— boots a Python interpretersdk/go/pulumi-language-go/— compiles and runs Go programssdk/pcl/cmd/pulumi-language-pcl/— runs PCL (the intermediate language)
.NET, Java, and YAML hosts live in their own repositories.
Providers — external repositories
Provider plugins (pulumi-resource-aws, pulumi-resource-kubernetes, etc.) implement proto/pulumi/provider.proto. They live outside this repo. The engine talks to them over gRPC just like it talks to language hosts. Two notable exceptions are present here:
- Default providers — synthetic providers materialized by the engine when the user doesn't construct one explicitly (
pkg/resource/deploy/providers/). - Test providers — built-in fake providers used by lifecycle tests (
tests/testprovider/).
Storage backends — pkg/backend/
Backends persist the state snapshot that the engine produces. Two implementations:
pkg/backend/diy/— do-it-yourself backend (filesystem, S3, GCS, Azure Blob viagocloud.dev/blob).pkg/backend/httpstate/— Pulumi Cloud (the hosted service atapp.pulumi.com).
Both implement the Backend interface from pkg/backend/backend.go. See systems/backend.
gRPC protocol — proto/pulumi/
Everything between processes is defined in Protobuf. The major service surfaces:
| File | Purpose |
|---|---|
proto/pulumi/resource.proto |
ResourceMonitor — language host → engine (Register, Read, Invoke, Call) |
proto/pulumi/engine.proto |
Engine — language host → engine (logging, root URN, etc.) |
proto/pulumi/provider.proto |
ResourceProvider — engine → provider plugin (Check, Diff, Create, Update, Delete) |
proto/pulumi/language.proto |
LanguageRuntime — engine → language host (GetRequiredPackages, Run, Pack) |
proto/pulumi/analyzer.proto |
Analyzer — engine → policy pack |
proto/pulumi/converter.proto |
Converter — pulumi convert plumbing |
proto/pulumi/plugin.proto |
Generic plugin metadata |
proto/pulumi/callback.proto |
Callbacks (transforms, hooks) |
Generated code is committed under sdk/proto/go/, sdk/nodejs/proto/, and sdk/python/lib/pulumi/runtime/proto/. Regenerate via make build_proto. CI enforces freshness via make check_proto (Makefile).
Code generation — pkg/codegen/
The codegen subsystem has two distinct jobs:
- SDK generation — produce a typed library for a given Pulumi schema (
pkg/codegen/{go,nodejs,python}). - Program generation — convert PCL programs into target-language programs, and (via converter plugins) convert from Terraform/CloudFormation/Kubernetes YAML into PCL. See
pkg/codegen/hcl2/for PCL-side handling andpkg/codegen/convert/for the conversion pipeline.
See systems/codegen.
End-to-end: what happens during pulumi up
sequenceDiagram
participant User
participant CLI as pulumi CLI
participant Engine as Deployment engine
participant Host as Language host
participant Prog as User program
participant Prov as Provider plugin
participant BE as Backend
User->>CLI: pulumi up
CLI->>BE: load latest snapshot
BE-->>CLI: previous state
CLI->>Engine: Update(target=stack, source=program)
Engine->>Host: spawn pulumi-language-<lang>
Engine->>Host: Run(program path, monitor address)
Host->>Prog: execute
Prog->>Engine: RegisterResource(type, name, inputs) [via ResourceMonitor]
Engine->>Prov: spawn + Configure
Engine->>Prov: Check(inputs), Diff(old,new), Create/Update/Delete
Prov-->>Engine: physical id + outputs
Engine-->>Prog: resource outputs
Prog->>Engine: SignalAndWaitForShutdown
Engine->>BE: persist new snapshot
Engine-->>CLI: exit code + summaryThe engine's job is to interleave the language-host events ("here is the desired state") with provider RPCs ("here is what changed in the cloud") and persist the result.
Where to start reading
If you have one hour: read docs/architecture/README.md, then pkg/cmd/pulumi/pulumi.go, then pkg/engine/update.go, then pkg/resource/deploy/deployment.go. After that the rest of the engine starts to make sense.
If you have one day, follow the lifecycle of a single resource: sdk/go/pulumi/resource.go (NewResource) → sdk/go/pulumi/context.go (registerResource) → engine pkg/resource/deploy/source_eval.go (monitor) → pkg/resource/deploy/step_generator.go → pkg/resource/deploy/step.go → provider RPC.
See systems/engine for that walkthrough in more depth.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.