The pulumi refresh command doesn’t actually update your cloud resources; it reads their current state to make sure your Pulumi state file accurately reflects what’s deployed in your cloud provider.

Let’s see it in action. Imagine you have a simple Pulumi program that creates an AWS S3 bucket.

import pulumi
import pulumi_aws as aws

bucket = aws.s3.Bucket("my-bucket")

pulumi.export("bucket_name", bucket.id)

After running pulumi up, you might decide to manually change the bucket’s public access settings directly in the AWS console, perhaps to block all public access.

pulumi up
# ... output showing the bucket being created ...

Now, if you run pulumi refresh, Pulumi will go to AWS, check the current configuration of my-bucket, and update its internal state file to match. It won’t change the bucket back to what your program defined; it just synchronizes Pulumi’s understanding.

pulumi refresh
# ... output showing the refresh process, potentially noting drift ...

The core problem pulumi refresh solves is drift: the divergence between your declared infrastructure (in Pulumi code and state) and the actual state of your resources in the cloud. This drift can happen for many reasons: manual changes in the cloud console, other automation tools modifying resources, or even intermittent cloud provider issues that cause a resource to enter an unexpected state. Without refresh, your pulumi up commands might operate on stale information, leading to unexpected behavior, errors, or even unintended resource modifications.

Internally, pulumi refresh works by iterating through all the resources managed by your Pulumi stack. For each resource, it queries the respective cloud provider’s API to get the current properties of that resource. This live data is then used to update the Pulumi state file, which is essentially a JSON document tracking all your deployed resources and their attributes. If a property in the state file doesn’t match the property returned by the cloud provider, Pulumi marks it as "drifted."

The primary lever you control with refresh is ensuring your Pulumi state is an accurate reflection of reality. You don’t directly configure refresh itself with flags that change how it refreshes (beyond targeting specific resources), but its output is crucial for subsequent pulumi up operations. For example, if refresh detects drift, a subsequent pulumi up will typically try to reconcile that drift by updating the resource to match your program’s desired state.

Consider this scenario: you have an EC2 instance defined in Pulumi, but someone manually scaled up the instance_type in the AWS console.

import pulumi
import pulumi_aws as aws

instance = aws.ec2.Instance("my-instance",
    ami="ami-0c55b159cbfafe1f0", # Example AMI ID
    instance_type="t2.micro")

pulumi.export("instance_public_ip", instance.public_ip)

If you run pulumi refresh, Pulumi will see the instance is now a t2.large (or whatever it was changed to). Your Pulumi.yaml and Pulumi.<stack-name>.yaml files will remain unchanged, but the Pulumi.<stack-name>.state.json file will be updated to reflect the t2.large type.

Then, if you run pulumi up, Pulumi will compare the desired state (t2.micro) with the refreshed state (t2.large) and, by default, will propose to change the instance back to t2.micro. This is how refresh enables up to correct drift.

The refresh command also has an --skip-preview flag. If you use this, pulumi refresh will update the state file but will not show you any detected drift. This can be useful in automated pipelines where you trust the refresh to happen silently, but it bypasses the visual confirmation of drift, which can be essential for debugging.

A common misconception is that pulumi refresh will redeploy resources or apply changes. It does neither. It’s a read-only operation against your cloud provider. Its sole purpose is to synchronize Pulumi’s internal representation of your infrastructure with the live state of those resources in the cloud. This synchronization is critical because Pulumi’s up command relies on having an accurate starting point. Without a fresh state, up might miss drift or attempt to modify resources based on outdated information, potentially leading to errors or unintended consequences.

One subtle but critical aspect of pulumi refresh is how it handles resources that have been deleted from the cloud but are still present in your Pulumi state. When refresh runs, it will detect that these resources no longer exist in the cloud and will remove them from your Pulumi state file. This prevents future pulumi up commands from trying to update or manage non-existent resources, which would otherwise result in errors.

The next logical step after understanding refresh is exploring how Pulumi handles multiple providers and how refresh interacts with them, especially in complex, multi-cloud or hybrid environments.

Want structured learning?

Take the full Pulumi course →