Skip to content

Architecture

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:

  1. Receives resource registration requests from language hosts via gRPC.
  2. Builds a dependency graph of all resources in the program.
  3. Dispatches CRUD operations to the appropriate provider plugin.
  4. Maintains a snapshot (state) of all deployed resources.
  5. 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 RegisterResource and RegisterResourceOutputs messages 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, streaming RegisterResource calls 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):

urn:pulumi:<stack>::<project>::<type>::<name>

Example:

urn:pulumi:production::my-app::aws:s3/bucket:Bucket::my-bucket

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 (props argument). Can be plain values, Promises, or Output<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


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

  1. Schema translation: The bridge reads the Terraform provider's JSON schema and generates Pulumi SDK types (TypeScript, Python, Go, etc.)
  2. Resource lifecycle mapping: Terraform's Create/Read/Update/Delete CRUD functions map directly to Pulumi's provider gRPC interface
  3. 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.

Sources