Pulumi is an open-source infrastructure as code platform that lets engineers declare cloud resources in general-purpose programming languages such as TypeScript, JavaScript, Python, Go, C#, Java and YAML, and then provisions those resources through a desired-state engine. In cloud infrastructure work, it occupies the same role as Terraform or OpenTofu but replaces a domain-specific configuration language with ordinary code.
The program does not call cloud APIs directly. It builds a resource graph, and the Pulumi engine compares that graph with the recorded state to compute the creates, updates and deletes required, which keeps the model declarative in outcome even though it is written imperatively.
How Pulumi turns a program into infrastructure
A Pulumi deployment involves three cooperating parts: the language host that executes the user’s program, the deployment engine that plans and orders changes, and resource providers that talk to cloud APIs. When the program constructs an object such as a storage bucket, it registers a resource registration with the engine instead of creating anything immediately.
Values that are not known until deployment, such as an assigned IP address, are represented as outputs, which behave like promises. Passing one resource’s output into another resource’s input creates a dependency edge, so the engine knows to create the network before the virtual machine that needs it.
| Component | Responsibility | Example |
|---|---|---|
| Project | Directory with program and Pulumi.yaml | A networking repository |
| Stack | Isolated instance with its own config and state | dev, staging, prod |
| Resource | One managed cloud object | A VPC, a DNS record, a role |
| Provider | Plugin that calls a cloud or SaaS API | AWS, Azure, Kubernetes |
| Component resource | Reusable group of child resources | A standard web service pattern |
| State backend | Stores the last known resource state | Managed service or object storage |
The usual workflow is pulumi preview to show the planned diff, followed by pulumi up to apply it. pulumi refresh reconciles state with reality, and pulumi destroy removes every resource in a stack.
State, stacks and configuration
Pulumi relies on state in the same way Terraform does: a record of every managed resource, its inputs, outputs and provider identity. Without accurate state the engine cannot tell whether a resource needs an update or a replacement, so protecting and locking state is a core operational duty.
State can live in the vendor’s managed cloud backend, which adds concurrency locking, history and access control, or in a self-managed backend such as an object storage bucket or the local file system. Each stack has its own configuration file, where values can be marked as secrets and stored encrypted with a passphrase, a cloud key management service or the managed backend.
| Backend | Locking and history | Typical fit |
|---|---|---|
| Managed service | Built in, with audit trail | Teams wanting minimal setup |
| Object storage bucket | Basic locking, history via versioning | Self-hosted or regulated teams |
| Local file system | None beyond one machine | Experiments and tutorials |
Pulumi compared with other infrastructure as code tools
Pulumi differs from its neighbors mainly in authoring language, not in its execution model. Like Terraform and AWS CloudFormation, it computes a desired state and reconciles it, whereas configuration management tools such as Ansible focus on configuring servers step by step.
| Tool | Authoring language | State handling | Scope |
|---|---|---|---|
| Pulumi | TypeScript, Python, Go, C#, Java, YAML | Pulumi state backend | Multi-cloud and SaaS |
| Terraform / OpenTofu | HCL | Terraform state file | Multi-cloud and SaaS |
| AWS CloudFormation | JSON or YAML templates | Managed by AWS | AWS only |
| Bicep | Bicep language | Azure Resource Manager | Azure only |
| Ansible | YAML playbooks | Mostly stateless | Server configuration |
Real programming languages bring loops, functions, classes, package managers, unit tests and IDE type checking to infrastructure. Pulumi can also consume many Terraform providers through a bridge, and its tooling can convert HCL programs into supported languages, which eases migration.
Practical use and design choices
Pulumi fits best where infrastructure and application teams share one language and want to reuse engineering practices such as code review, packaging and testing. Platform teams often publish component resources as internal libraries so that product teams create a compliant service with a few lines of code.
- Stack per environment: separate dev, staging and production stacks with stack references for shared outputs.
- Policy as code: CrossGuard policies written in TypeScript, Python or OPA Rego block noncompliant changes before deployment.
- Automation API: embeds the engine inside a program, enabling self-service portals and custom deployment workflows.
- Unit and integration tests: mocks test resource logic without cloud calls; ephemeral stacks test real deployments.
The decisive design rule is to keep programs deterministic: the same inputs must produce the same resource graph, otherwise every preview shows spurious changes.
Pitfalls and common mistakes
The flexibility of a full language is also Pulumi’s most common source of trouble. Code that is easy to write can be hard for reviewers to predict, and the following problems recur in real projects.
| Symptom | Cause | Fix |
|---|---|---|
| Resource replaced unexpectedly | Changed logical name or immutable property | Use aliases, review previews carefully |
| Noisy diffs on every run | Timestamps or random values in code | Use stable inputs or the random provider |
| Values printed as undefined | Reading an output outside apply | Transform outputs with apply or interpolation |
| Configuration drift | Manual console changes | Run refresh, restrict console write access |
| Leaked secrets in logs | Plain config for sensitive values | Mark values as secrets |
Teams should also avoid calling cloud SDKs directly inside the program to create resources, because those objects bypass state and become invisible to the engine.
Understanding it simply
Pulumi lets engineers describe servers, networks and databases by writing ordinary program code, the same kind of code they use to build applications. The code is a blueprint, and Pulumi builds whatever the blueprint describes in the cloud.
When the blueprint changes, Pulumi compares it with what already exists and changes only the difference, much like a contractor who reads revised building plans and adds one room instead of rebuilding the house. Because everything is written down, the same setup can be rebuilt reliably at any time.
Applied in practice
A platform team in a mid-sized software company writes most of its services in TypeScript. It creates a Pulumi component called a standard service that bundles a container service, a load balancer, a DNS record, log retention of 30 days and alarms. Product teams install it as an internal package and declare a new service in about twenty lines of code.
Each repository has dev, staging and prod stacks. Every pull request runs pulumi preview in the pipeline, and policy checks reject any public storage bucket. After adoption, new services reach staging on the same day instead of after a week of tickets, and every environment is reproducible from version control.