Fork me on GitHub

How Pulumi Works

When a Pulumi program is deployed via pulumi update, there are a few processes involved. The language host launches Node or Python and observes the running program. The host interacts with the Pulumi engine, which is the part of the CLI that determines which resource changes to make (if any). Any resource changes are then executed via an underlying provider, such as AWS, Azure, Kubernetes, and so on. The engine connects to to retrieve the stack’s checkpoint, which stores the last known state of provisioned resources.

During program execution, whenever there is a resource creation statement (via new Resource() in JavaScript or Resource(...) in Python), the resource is registered with the engine. This does not necessarily mean that a new resource should be created, it simply means that the program intends for the resource to exist. Using the last state in the checkpoint stored on, the engine determines which requests it should make to the underlying provider in order to create, delete, or replace the resource. At the end the program execution, if a particular resource R is never registered, the engine will make a delete request to the resource provider. The following diagram illustrates the interaction between these parts of the system.

Pulumi engine and providers

For instance, suppose we have the following Pulumi program, which creates two S3 buckets:

const bucket = new aws.s3.Bucket("media-bucket");
const bucket = new aws.s3.Bucket("content-bucket");

Now, we run pulumi stack init mystack. Since mystack is a new stack, the “last deployed state” has no resources.

Next, we run pulumi update. When the program runs to completion, it runs the two new aws.s3.Bucket() statements. So, the language host registers two resources with the engine.

The engine consults the last deployed state on, and determines that these resources do not already exist. So, the engine calls the AWS resource provider, requesting that it create a security group. Once the operation succeeds, this state is written to the last-deployed checkpoint. So, the resource list will be similar to the following:

stack mystack
   - aws.s3.Bucket "media-bucket653a4"
   - aws.s3.Bucket "content-bucket125ce"

Now, suppose we rename content-bucket to app-bucket:

const bucket = new aws.s3.Bucket("media-bucket");
const bucket = new aws.s3.Bucket("app-bucket"); // renamed bucket

This time, the engine will not create another media-bucket, since it exists in the checkpoint. Now, since an S3 bucket cannot be renamed in place, the engine makes a “replace” call to the AWS provider. The provider deletes the bucket content-bucket125ce and creates a new one.