Resource option: stateMigrations
The stateMigrations resource option lets a component author supply an ordered list of callbacks that translate the component’s prior state and the state of its children before diffing. Use it when a new component version changes its internal resource structure while preserving existing cloud resources.
stateMigrations resource option applies to both custom resources and component resources. It is defined on the base resource-options type in every Pulumi SDK.This API is experimental and may change.
Callback API
Each migration callback is a pure function that transforms the saved state of a component and its children into the state expected by a new component version.
Each callback receives the registering component’s URN and the prior state of the component and its descendants. It returns a complete replacement state and, when removing or renaming resource URNs, a mapping from each old URN to its successor. Returning no result leaves the state unchanged and allows later callbacks to run.
The prior subtree contains the component itself first and then its descendants in checkpoint resource format. The registering URN can differ from the root’s prior URN when Pulumi matches it through an alias. Each callback receives the preceding callback’s result.
A changed result must contain the entire replacement subtree, including unchanged resources. Every input URN must either remain in the result or have a successor mapping to a resource in the result, but not both. Multiple removed URNs can map to the same successor.
Example
Define a migration callback and pass it to a component through the stateMigrations option.
import * as pulumi from "@pulumi/pulumi";
// Shape of pulumi.StateMigrationArgs, shown here for reference.
type StateMigrationArgs = {
urn: pulumi.URN;
oldState: Record<string, any>[];
};
// Shape of pulumi.StateMigrationResult, shown here for reference.
type StateMigrationResult = {
newState: Record<string, any>[];
successors?: Record<pulumi.URN, pulumi.URN>;
};
function migrate(args: pulumi.StateMigrationArgs): pulumi.StateMigrationResult | undefined {
// args.urn identifies the component being registered.
// args.oldState contains the component's prior state and its descendants.
// Return { newState, successors } when the state needs migration.
return undefined;
}
const component = new MyComponent("example", {}, {
stateMigrations: [migrate],
});
API reference: StateMigrationArgs · StateMigrationResult.
from typing import Any
import pulumi
# Fields of pulumi.StateMigrationArgs, shown here for reference.
class StateMigrationArgs:
urn: str
old_state: list[dict[str, Any]]
# Fields of pulumi.StateMigrationResult, shown here for reference.
class StateMigrationResult:
new_state: list[dict[str, Any]]
successors: dict[str, str] | None
def migrate(args: pulumi.StateMigrationArgs) -> pulumi.StateMigrationResult | None:
# args.urn identifies the component being registered.
# args.old_state contains the component's prior state and its descendants.
# Return pulumi.StateMigrationResult(new_state=..., successors=...) when needed.
return None
component = MyComponent(
"example",
opts=pulumi.ResourceOptions(state_migrations=[migrate]),
)
API reference: StateMigrationArgs · StateMigrationResult.
// Shape of pulumi.StateMigrationArgs, shown here for reference.
type StateMigrationArgs struct {
URN pulumi.URN
OldState []map[string]any
}
// Shape of pulumi.StateMigrationResult, shown here for reference.
type StateMigrationResult struct {
NewState []map[string]any
Successors map[string]string
}
migrate := func(_ context.Context, args *pulumi.StateMigrationArgs) (*pulumi.StateMigrationResult, error) {
// args.URN identifies the component being registered.
// args.OldState contains the component's prior state and its descendants.
// Return &pulumi.StateMigrationResult{NewState: ..., Successors: ...}, nil when needed.
return nil, nil
}
component, err := NewMyComponent(ctx, "example",
pulumi.StateMigrations([]pulumi.StateMigration{migrate}),
)
if err != nil {
return err
}
API reference: StateMigrationArgs · StateMigrationResult.
See the state migrations guide for a complete example.
Behavior
Callbacks run during previews and updates when prior state exists. They must be idempotent and return no result when the state no longer needs migration. They rewrite state without performing provider operations.
Callbacks must preserve managed resource identity, lifecycle safety flags, and secret envelopes. They must not perform Pulumi runtime operations or wait for unresolved outputs.
See State migrations for the full contract, restrictions, and complete examples.