Architecture¶
See also
index | architecture | operations | security | index#Questions
Pulumi is an infrastructure-as-code platform that allows users to define cloud resources using general-purpose programming languages (TypeScript, Python, Go, .NET, Java) instead of a domain-specific language. The engine compiles user programs into resource declarations, then reconciles desired state against real infrastructure via provider plugins.
Component Overview¶
graph TB
subgraph USER["User Program"]
TS["TypeScript / Node.js"]
PY["Python"]
GO["Go"]
CS[".NET / C#"]
JA["Java"]
end
subgraph LH["Language Host Plugins"]
LHN["Node.js Host"]
LHP["Python Host"]
LHG["Go Host"]
LHD[".NET Host"]
end
subgraph ENGINE["Pulumi Engine"]
RC["Resource Coordinator"]
RG["Resource Graph<br/>(DAG)"]
DISP["Dispatcher"]
SNAP["Snapshot / State"]
end
subgraph PROV["Provider Plugins"]
PAWS["AWS Provider"]
PAZURE["Azure Provider"]
PGCP["GCP Provider"]
PK8S["Kubernetes Provider"]
PBRIDGE["Terraform Bridge<br/>Providers"]
end
subgraph BACKEND["State Backend"]
PCLOUD["Pulumi Cloud<br/>(SaaS)"]
SELF["Self-managed<br/>(S3, Azure Blob, local)"]
ESC["Pulumi ESC<br/>(Secrets & Config)"]
end
TS --> LHN
PY --> LHP
GO --> LHG
CS --> LHD
JA --> LHN
LHN -->|gRPC| ENGINE
LHP -->|gRPC| ENGINE
LHG -->|gRPC| ENGINE
LHD -->|gRPC| ENGINE
RC --> RG
RG --> DISP
DISP -->|gRPC| PAWS
DISP -->|gRPC| PAZURE
DISP -->|gRPC| PGCP
DISP -->|gRPC| PK8S
DISP -->|gRPC| PBRIDGE
RC --> SNAP
SNAP --> PCLOUD
SNAP --> SELF
ESC --> RC
Engine¶
The Pulumi engine (pulumi-language-go, pulumi/pkg/engine) is the central orchestrator written in Go. It:
- Receives resource registration requests from language hosts via gRPC.
- Builds a dependency graph of all resources in the program.
- Dispatches CRUD operations to the appropriate provider plugin.
- Maintains a snapshot (state) of all deployed resources.
- Detects drift by comparing the snapshot with real infrastructure during refreshes.
The engine runs as a single process that communicates with language hosts and provider plugins as separate subprocesses.
Language Host Plugins¶
Unlike Terraform's HCL-only approach, Pulumi supports multiple programming languages through language host plugins. Each host is responsible for:
- Executing the user's program.
- Intercepting resource constructor calls (
new aws.s3.Bucket(...),aws.s3.Bucket(...)). - Translating those calls into gRPC
RegisterResourceandRegisterResourceOutputsmessages sent to the engine.
| Language Host | SDK Package | Runtime |
|---|---|---|
| Node.js | @pulumi/pulumi |
Node.js 18+ |
| Python | pulumi (pip) |
CPython 3.8+ |
| Go | github.com/pulumi/pulumi/sdk/v3/go/pulumi |
Go 1.21+ |
| .NET | Pulumi (NuGet) |
.NET 6+ |
| Java | com.pulumi (Maven) |
JDK 11+ |
The language host protocol is defined as a gRPC service (pulumirpc.LanguageRuntime) with methods:
GetRequiredPlugins-- declares which providers the program needs.Run-- executes the program, streamingRegisterResourcecalls back to the engine.
Resource Model¶
Resource Types¶
Pulumi defines two primary resource abstractions:
| Type | Purpose | Example |
|---|---|---|
| CustomResource | Maps to a single cloud resource | aws.s3.Bucket, azure.compute.VirtualMachine |
| ComponentResource | Logical grouping of child resources | awsx.ec2.Vpc, custom abstractions |
Resource URN¶
Every resource is identified by a URN (Uniform Resource Name):
Example:
The URN encodes the stack, project, resource type, and logical name. It serves as the stable identifier across updates.
Inputs and Outputs¶
- Inputs: Values passed to a resource constructor (
propsargument). Can be plain values, Promises, orOutput<T>. - Outputs: Represent values that may not be known until after deployment.
Output<T>tracks dependencies automatically and propagates secrets.
Output<T> is Pulumi's core mechanism for chaining resource dependencies:
const bucket = new aws.s3.Bucket("my-bucket");
const obj = new aws.s3.BucketObject("my-object", {
bucket: bucket.bucket, // Output<string> -- dependency tracked
});
Provider Plugins¶
Providers are separate processes that communicate with the engine over gRPC (pulumirpc.ResourceProvider service).
Provider Lifecycle RPCs¶
sequenceDiagram
participant Engine as Pulumi Engine
participant Provider as Provider Plugin (e.g., aws)
Engine->>Provider: GetSchema
Provider-->>Engine: JSON Schema
Engine->>Provider: Configure (credentials, region)
Provider-->>Engine: ConfigureResponse
loop For each resource
Engine->>Provider: Check (validate inputs)
Provider-->>Engine: CheckResponse
Engine->>Provider: Diff (detect changes)
Provider-->>Engine: DiffResponse
alt Create
Engine->>Provider: Create
Provider-->>Engine: CreateResponse (id + outputs)
else Update
Engine->>Provider: Update
Provider-->>Engine: UpdateResponse
else Delete
Engine->>Provider: Delete
Provider-->>Engine: empty
end
end
Terraform Bridge¶
The Terraform Bridge (pulumi-terraform-bridge) wraps existing Terraform providers as Pulumi providers. This gives Pulumi access to 4,800+ providers without re-implementing them. The bridge translates between Pulumi's gRPC protocol and Terraform's provider protocol.
Key bridge components: - Schema translation: Converts Terraform provider schemas to Pulumi schemas. - Resource mapping: Maps Terraform resource types to Pulumi resource types. - State conversion: Translates between Terraform state format and Pulumi state format.
Resource Lifecycle Diagram¶
flowchart TD
A[User runs pulumi up] --> B[Language host executes program]
B --> C[Program registers resources via SDK]
C --> D[Engine builds resource DAG]
D --> E{Resource exists in state?}
E -->|No| F[Create: provider.Create]
E -->|Yes| G[Diff: provider.Diff]
G --> H{Changes detected?}
H -->|No change| I[No-op, keep existing]
H -->|In-place update| J[Update: provider.Update]
H -->|Requires replacement| K[Create new + Delete old]
F --> L[Update state snapshot]
J --> L
K --> L
I --> L
L --> M{More resources?}
M -->|Yes| E
M -->|No| N[Persist final snapshot to backend]
State Management¶
State Backend Options¶
| Backend | Type | State Locking | Secrets Encryption |
|---|---|---|---|
| Pulumi Cloud | Managed SaaS | Yes | Yes (per-secret, server-side) |
| Self-managed (S3) | AWS S3 bucket | Yes (DynamoDB) | Local passphrase or cloud KMS |
| Self-managed (Azure Blob) | Azure storage | Yes (blob lease) | Local passphrase |
| Self-managed (local) | Local filesystem | No | Local passphrase |
State Format¶
- Stored as a JSON snapshot containing every resource's URN, type, inputs, outputs, and provider reference.
- Secrets within state are individually encrypted (not just the whole file), allowing selective decryption.
- Each update creates a new checkpoint (versioned history in Pulumi Cloud).
Stack References¶
Stack references allow one stack to read outputs from another:
const otherStack = new pulumi.StackReference("org/other-project/prod");
const vpcId = otherStack.getOutput("vpcId");
Automation API¶
The Automation API enables embedding Pulumi directly within application code, creating custom deployment workflows without shelling out to the CLI:
import * as auto from "@pulumi/automation";
const stack = await auto.LocalWorkspace.createOrSelectStack({
stackName: "dev",
projectName: "my-app",
program: myPulumiProgram,
});
const upResult = await stack.up();
console.log(`Update succeeded: ${upResult.summary.result}`);
Key use cases: - Custom CLIs and developer portals. - CI/CD pipeline integration with fine-grained control. - Multi-stage deployment orchestrators. - SaaS provisioning systems.
Comparison with Terraform / OpenTofu¶
| Aspect | Pulumi | Terraform / OpenTofu |
|---|---|---|
| Language | General-purpose (TS, Python, Go, .NET, Java) | HCL (declarative DSL) |
| Provider ecosystem | Native + 4,800+ via Terraform Bridge | Native providers only |
| State secrets | Per-secret encryption | Whole-file (OpenTofu) or none (Terraform OSS) |
| Testing | Standard unit test frameworks | Limited (plan assertions, Sentinel) |
| Automation API | Built-in | Not available (CLI-only) |
| Component reuse | Standard language packages/modules | Terraform modules (HCL) |
References¶
- Pulumi documentation
- Pulumi GitHub repository
- Provider implementation guide
- Automation API documentation
- Terraform Bridge
How It Works¶
Language SDK runtime, provider plugin architecture, and deployment engine internals.
Deployment Engine¶
sequenceDiagram
participant User as User Code (TypeScript/Python/Go)
participant SDK as Pulumi Language SDK
participant Engine as Pulumi Engine
participant Provider as Provider Plugin (gRPC)
participant Cloud as Cloud API
User->>SDK: Declare resources (new aws.s3.Bucket(...))
SDK->>Engine: Register resource (gRPC)
Engine->>Engine: Build dependency graph
Engine->>Provider: Create/Update/Delete
Provider->>Cloud: API calls
Provider-->>Engine: Resource outputs
Engine-->>SDK: Resolve outputs (Promises/Futures)
SDK-->>User: Export outputs
Language Runtime Model¶
flowchart TB
subgraph User["User Process"]
Code["TypeScript / Python / Go\nInfra Code"]
SDK_P["Pulumi SDK\n(resource registration)"]
end
subgraph Engine_P["Pulumi Engine Process"]
Deployment["Deployment Engine\n(DAG, diffing, ordering)"]
StateM["State Manager"]
end
subgraph Providers_P["Provider Processes"]
AWS_P["AWS Provider"]
K8s_PP["K8s Provider"]
TF_Bridge["Terraform Bridge\n(use TF providers)"]
end
Code --> SDK_P
SDK_P <-->|"gRPC"| Deployment
Deployment <-->|"gRPC"| Providers_P
Deployment --> StateM
style User fill:#8b5cf6,color:#fff
style Engine_P fill:#1565c0,color:#fff
Terraform Bridge¶
Pulumi can use any Terraform provider via the Terraform Bridge -- a compatibility layer that translates Terraform provider schemas into Pulumi resource types. This gives Pulumi access to the same 4,800+ providers.
Bridge Internals¶
- Schema translation: The bridge reads the Terraform provider's JSON schema and generates Pulumi SDK types (TypeScript, Python, Go, etc.)
- Resource lifecycle mapping: Terraform's
Create/Read/Update/DeleteCRUD functions map directly to Pulumi's provider gRPC interface - State mapping: Terraform's flat state attributes are converted to Pulumi's structured resource outputs
Dependency Resolution¶
Pulumi automatically detects resource dependencies from program flow:
const bucket = new aws.s3.Bucket("my-bucket");
const obj = new aws.s3.BucketObject("my-object", {
bucket: bucket.bucket, // implicit dependency: obj depends on bucket
source: new pulumi.asset.FileAsset("./dist/app.zip"),
});
The SDK captures all Output<T> references during resource registration. The engine builds a DAG from these references and executes independent resources in parallel while respecting dependency order.
State and Locking¶
Pulumi stores state in a backend (Pulumi Cloud, self-managed, or local filesystem):
- Checkpoint format: State is stored as a JSON blob containing all resource URNs, IDs, outputs, and dependency information
- Locking: The backend provides optimistic concurrency control via version numbers. If two concurrent updates attempt to modify the same stack, the second will fail with a conflict error
- Secrets: Sensitive outputs are encrypted at rest using a per-stack encryption key
Sources¶
Benchmarks¶
Scope
Performance characteristics, scaling limits, and resource consumption for Pulumi.
Deployment Performance¶
| Stack Size | Preview Time | Update Time | Notes |
|---|---|---|---|
| 50 resources | 5-10s | 1-3m | Quick iteration |
| 200 resources | 15-30s | 3-10m | Typical app stack |
| 1,000 resources | 1-3m | 10-30m | Large infrastructure |
Language Runtime Overhead¶
| Language | Cold Start | Warm Start | Memory |
|---|---|---|---|
| Go | 1-2s | < 1s | 50-100MB |
| TypeScript | 3-5s | 1-2s | 100-200MB |
| Python | 2-4s | 1-2s | 80-150MB |
| C# | 3-6s | 1-3s | 100-200MB |
Scaling Limits¶
| Dimension | Limit | Notes |
|---|---|---|
| Resources per stack | 10,000+ | Performance degrades beyond 5,000 |
| Stacks per project | Unlimited | Use stack references for composition |
| Concurrent operations | 1 per stack | Stack-level locking |
Sourcing Status¶
Unsourced Performance Data
The performance numbers in this document are estimated from vendor documentation, community benchmarks, and engineering judgment. They do not represent controlled benchmarks with documented test conditions. Specific hardware configurations, software versions, and test methodologies were not recorded.
Use these figures as rough guidance only. For production capacity planning, run your own benchmarks against your specific workload and infrastructure.