Back to Pulumi

Deployment Steps

docs/architecture/deployment-execution/steps.md

3.235.010.4 KB
Original Source

Deployment Steps

Deployments in Pulumi happen as a series of Steps. These are generated by the step generator, and then executed by the deployment executor.

When a Step is applied using the Apply() function, it interacts with backing providers to produce the function that will ultimately register the resource against Pulumi's desired state graph.

Each step also has an old and a new state, the old state representing the state we read from the snapshot, or the result of a previous step, and the new state representing the state that the step should have after the Apply().

Pulumi's deployment system uses different step types to represent the various operations that can be performed on resources. These steps fall into several categories:

Step Categories

Externally Mutating Steps directly modify resources via provider operations:

Non-Mutating Steps represent logical operations:

  • SameStep: Resource unchanged or skipped
  • ReplaceStep: Logical marker for replacements (combination of Create + Delete)

Special Steps handle specific scenarios:

Step Lifecycle

mermaid
sequenceDiagram
    participant SG as Step Generator
    participant SE as Step Executor
    participant E as Events
    participant P as Provider

    SG->>SE: Submit Step (in chain)
    SE->>E: OnResourceStepPre
    E-->>SE: payload
    SE->>SE: step.Apply()

    alt Custom Resource
        SE->>P: Create/Update/Delete/Read
        P-->>SE: Response + New State
    else Component/Preview
        SE->>SE: State manipulation only
    end

    SE->>E: OnResourceStepPost
    SE->>SE: stepComplete()
    SE-->>SG: Step finished

Each step follows this lifecycle:

  1. Generation: Step generator creates steps based on resource state and diff results
  2. Submission: Steps are submitted to the step executor in chains (serial sequences) or antichains (parallel sets)
  3. Pre-Event: OnResourceStepPre callback fires before execution
  4. Application: Step's Apply() method executes, potentially calling provider methods
  5. Post-Event: OnResourceStepPost callback fires after execution
  6. Completion: Step completion function signals to dependent steps

Replacement Workflows

Replacements come in two flavors:

Create-Before-Replace (Default)

The new resource is created first, then the old is deleted. Both resources exist in state temporarily, with the old marked Delete = true after creation. The ReplaceStep is created as a marker after the CreateStep is generated.

Delete-Before-Replace

The old resource is deleted first in the provider, but kept in the snapshot, marked as PendingReplacement. Then the new resource is created, removing the resource PendingReplacement from the state.

Step Properties

All steps implement the Step interface and have:

  • Old(): State before the step
  • New(): State after the step
  • Res(): Latest known state
  • Logical(): Whether this represents a logical program operation (vs. internal bookkeeping)
  • Apply(): Executes the step, returns status, completion function, and error

Step Details

SameStep

SameSteps are generated whenever a resource does not change. This can happen for example if we have an existing resource and the provider Diff call returns no changes, or if there's a targeted up, and the resource is not being targeted. We also use SameSteps for "skipped creates". Those are also emitted if a resource is not targeted, but is being created by the program.

Application

When this type of step is applied, we copy the old inputs to the new inputs, and complete the step. The completion function will mark the resulting state as the "new" state. If the step is skipped, we do no such copying.

CreateStep

CreateSteps are emitted whenever we want to create a new resource. Note that there are two variations of create steps, namely a regular create, and a create-replacement. The create step simply creates a new resource. A create-replacement step is generated when we do a replace of a resource. It is always returned combined with a ReplaceStep` (see below).

Application

During the application of the create step, we first run the BeforeCreate hooks. Then if we have a custom resource, we call Create on the provider to actually create the resource. For both Custom and Component resources we then update the "New" state, and finally call the AfterCreate hook once the resource creation is done.

If we have a create-replacement step, and the old resource is not yet deleted (i.e. it's not marked deleteBeforeReplace), we also mark the old resource as Delete. This allows us to keep both versions of the resource in the snapshot, and keep track of the resource that has not yet been deleted from the cloud provider. Note that this is one of the places where we edit the deployment state directly instead of through the snapshot manager.

DeleteStep

DeleteSteps are generated when a resource needs to be removed from the deployment. This includes resources removed from the program, replacements requiring deletion, or external resource discards.

Application

The delete step runs BeforeDelete hooks, checks for protection (failing if protected and not a replacement), and then:

  • In preview: synthesizes view steps but doesn't delete
  • External resources: no-op (Pulumi doesn't own lifecycle)
  • RetainOnDelete: deletion skipped
  • DeletedWith: skipped if parent is also being deleted
  • Custom resources: calls provider's Delete method

For delete-before-replace operations, the PendingReplacement flag is set after successful deletion. AfterDelete hooks run immediately for both custom and component resources (unlike Create/Update which defer component hooks to RegisterResourceOutputs).

UpdateStep

UpdateSteps modify existing resources when the provider indicates changes are needed that don't require replacement.

Application

The update step propagates the resource ID and timestamps, runs BeforeUpdate hooks, then calls the provider's Update method with old and new inputs/outputs. The provider returns updated outputs, and the modified timestamp is updated. For custom resources, AfterUpdate hooks run at completion; for component resources, they run during RegisterResourceOutputs.

ReplaceStep

ReplaceSteps are logical markers indicating a resource replacement. The actual work happens in the associated CreateStep and DeleteStep. This step exists for visualization and tooling purposes.

Application

The Apply method is essentially a no-op, verifying that pending delete resources are properly marked for deletion.

ReadStep

ReadSteps import existing resources as external references (marked with the External flag, meaning Pulumi doesn't own their lifecycle).

Application

The provider's Read method fetches the current cloud state. For ReadReplacement steps, the old managed resource is marked for deletion. Unlike most steps, Read steps execute during previews to fetch actual state.

RefreshStep

RefreshSteps update resource state by reading current provider state. Note that these steps can be issued either by the deployment executor or the step generator.

Application

Component resources, providers, and pending replacements aren't refreshed. For custom resources, the provider's Read fetches current state. If the provider returns a blank ID, the resource is considered deleted. A diff is computed showing changes between provider state and program's desired state (inverted from normal diff direction). The ResultOp method returns whether the resource is same, updated, or deleted.

ImportStep

ImportSteps bring existing cloud resources under Pulumi management (unlike ReadSteps which create external references).

Application

For custom resources, the provider's Read method fetches state using the ImportID. An "old" state is synthesized for diff display. For planned imports (from pulumi import command), the resource must not exist in state, and provider Check validates inputs. For import replacements, the original resource is marked for deletion.

RemovePendingReplaceStep

RemovePendingReplaceSteps clean up the PendingReplacement flag set during delete-before-replace operations.

Application

The Apply method is a no-op. This step exists for tracking and display purposes.

DiffStep

DiffSteps leverage the step executor's parallel worker pool for computing resource diffs during step generation.

Application

Calls the provider's Diff method and communicates results via a promise completion source rather than returning errors. Never participates in normal step error handling.

ViewStep

ViewSteps are virtual steps for view resources. They communicate what happened to views for display and analysis, but don't perform provider operations.

Application

The Apply method is mostly a no-op. For OpCreateReplacement view steps, it marks the old resource for deletion. Returns the recorded status and error.