Pulumi Infrastructure with Python — Core Concepts
Why Pulumi exists
Infrastructure as Code (IaC) tools let teams define cloud resources in files instead of clicking through web consoles. Terraform pioneered this with HCL, a domain-specific language. Pulumi’s insight was: developers already know programming languages — why not use those?
Pulumi supports Python, TypeScript, Go, and C#. For Python teams, this means infrastructure and application code share the same language, tooling, testing frameworks, and package ecosystem.
The programming model
A Pulumi program is a regular Python script that imports cloud resource classes from Pulumi provider packages. When you instantiate a resource class, Pulumi registers it with its engine:
import pulumi
import pulumi_aws as aws
bucket = aws.s3.Bucket("my-data-bucket",
versioning=aws.s3.BucketVersioningArgs(
enabled=True,
),
)
pulumi.export("bucket_name", bucket.id)
This creates an S3 bucket with versioning. The key difference from Terraform: this is real Python. You can use loops, conditionals, functions, and classes.
Core concepts
Resources are the building blocks — an AWS EC2 instance, a Google Cloud SQL database, an Azure Function. Each resource has inputs (configuration) and outputs (values like IPs and ARNs that are known only after creation).
Stacks represent different instances of your infrastructure — typically one per environment (dev, staging, production). Each stack has its own state and configuration values.
Outputs are special values that might not be known until deployment. Pulumi handles these with a promise-like system — you can chain transformations on outputs without knowing their concrete values yet.
State is stored in Pulumi Cloud (free tier available), an S3 bucket, or local files. The state tracks what resources exist so Pulumi can compute diffs.
How deployment works
Running pulumi up executes your Python program, builds a desired-state resource graph, compares it against the stored state, and shows a diff:
Previewing update:
+ aws:s3:Bucket my-data-bucket create
~ aws:ec2:Instance web-server update [image changed]
- aws:rds:Instance old-db delete
Resources:
+ 1 to create
~ 1 to update
- 1 to delete
You confirm, and Pulumi applies changes in dependency order — creating the bucket before anything that references it, deleting resources only after dependents are removed.
Python advantages in practice
Abstraction through classes. Teams create component resources — Python classes that bundle related infrastructure. A WebService class might create a load balancer, autoscaling group, DNS record, and SSL certificate together.
Testing. Because it’s Python, you can write unit tests with pytest that verify your infrastructure code produces correct resource configurations — without deploying anything.
Type checking. Pulumi’s Python SDK includes type hints, so mypy and IDE autocomplete work. You get errors before deployment, not during.
Package reuse. Publish your infrastructure components as pip packages. Other teams install them with pip install your-infra-lib and use them like any Python library.
Common misconception
People assume Pulumi is “just Terraform with Python syntax.” While the end result (cloud resources) is similar, Pulumi’s model is fundamentally different. Terraform processes a static configuration; Pulumi executes a program. This means you can fetch data from APIs, read files, compute values dynamically, and use any Python library during resource definition — things that require awkward workarounds in Terraform.
When to choose Pulumi
Pulumi makes sense when your team is Python-first, when you need complex logic in infrastructure definitions, or when you want to share patterns as pip-installable libraries. Terraform remains a strong choice for teams that prefer a declarative-only approach or need the broadest ecosystem of community modules.
The one thing to remember: Pulumi turns cloud infrastructure into a Python programming problem, giving teams loops, classes, tests, and package management for their infrastructure — not just their application code.
See Also
- Python Ansible Automation How Python powers Ansible to automatically set up and manage hundreds of servers without logging into each one
- Python Docker Compose Orchestration How Python developers use Docker Compose to run multiple services together like a conductor leading an orchestra
- Python Etcd Distributed Config How Python applications use etcd to share configuration across many servers and react to changes instantly
- Python Helm Charts Python Why Python developers use Helm charts to package and deploy their apps to Kubernetes clusters
- Python Nomad Job Scheduling How Python developers use HashiCorp Nomad to run their programs across many computers without managing each one