2.8. State Management
Pulumi’s state file is the source of truth for every deployed resource — its properties, outputs, and dependencies. This lab covers how to inspect it, detect drift, and perform surgical repairs.
Step 1 — Inspect the state file
Export the full state and browse it with jq:
Find all container resources and list their URNs:
You should see two URNs — one for blue-container and one for green-container. Note the blue-container
URN — you will need it in Step 3.
Explanation
pulumi stack export writes the full stack state to stdout as a JSON document. The top-level structure is:
Each entry in resources represents one managed resource and records everything Pulumi knows about it:
the provider, the logical name, the physical name, all input and output properties, and the list of
resource URNs it depends on.
The state is what makes pulumi preview possible — Pulumi diffs your program against this file rather than
querying the live infrastructure on every run.
State backends
The state file lives in a backend — the storage location Pulumi uses for a given project:
| Backend | When to use |
|---|---|
Local (--local) | Solo dev and this lab — file on your laptop |
| Pulumi Cloud | Managed backend with UI, history, and RBAC |
| Azure Blob / S3 | Self-hosted team backend — the pattern for customer projects |
In the Azure lab you will move to an Azure Blob backend so the state is shared across the team and survives beyond your laptop.
Step 2 — Detect and repair drift
Pulumi’s desired state lives in code; drift happens when someone changes infrastructure outside Pulumi — a container stopped via the CLI, a resource deleted in the Azure portal, a tag edited by hand.
Force drift by removing the blue container directly from Docker:
Confirm only green remains:
Now run pulumi refresh to compare the state file against live infrastructure:
Observe the output — Pulumi detects blue-container is missing and marks it for replacement. Bring the
stack back to the desired state:
Explanation
pulumi refresh queries the actual infrastructure (Docker, Azure, …) for every resource in the state file
and reconciles any differences it finds:
| What refresh does | Result |
|---|---|
| Resource still exists, matches | No change |
| Resource exists but drifted | State updated to reflect actual properties |
| Resource is gone | State marks the resource as needing recreation |
After pulumi refresh, the state accurately reflects reality. pulumi up then applies only the changes
needed to reach the desired state — in this case, recreating blue-container.
Refresh before up in production
In long-running environments it is good practice to run pulumi refresh before pulumi up so you are
diffing against reality rather than a potentially stale state file.
Step 3 — Surgical state repairs
Sometimes a resource is deleted out-of-band and you do not want Pulumi to recreate it — you want Pulumi
to simply forget it. pulumi state delete removes a resource from the state file without touching the
actual infrastructure.
Look up the URN for blue-container (you noted it in Step 1):
Remove blue-container from state using the URN:
Confirm only one container remains in state, while both are still running in Docker:
Run pulumi up to bring state and reality back in sync — Pulumi recreates blue-container since it is
declared in code but absent from state:
Explanation
pulumi state delete is a break-glass tool for situations pulumi refresh cannot handle — for example,
a resource that was deleted in the Azure portal in a way that left its provider in an error state, or a
resource you want to hand off to another stack.
| Command | What it does |
|---|---|
pulumi refresh | Syncs state to reality — updates or marks missing resources |
pulumi state delete <urn> | Removes the resource from state; leaves real infrastructure alone |
pulumi state unprotect <urn> | Clears the protect flag in state without changing code |
pulumi state unprotect is the counterpart to protect=True in ResourceOptions — useful when a
protected resource must be deleted urgently and re-deploying to flip the flag is not an option.
URNs encode the full parent chain
A URN encodes the stack, project, parent chain, resource type, and logical name. For a top-level resource:
For a resource nested inside a component, the parent type is prepended with $:
This is why blue-container’s URN contains workshop:index:WebServer$docker:index/container:Container —
it lives inside the blue WebServer component.
The URN is stable as long as you do not rename the resource or move it to a different parent. Either change causes a delete-and-recreate.