1. Docs
  2. Infrastructure as Code
  3. Concepts
  4. Stash

Stash

    The Stash resource is a built-in Pulumi resource that allows you to save values to your stack’s state for later retrieval. A stash takes a single input value and stores it in state, making it available as an output property. Stashes are commonly used to persist computed values, pass data between program executions, or save intermediate results that need to be accessed later.

    Every Stash resource accepts any value as its input property and makes that value available through its output property. The output value is stateful and persists the original input value even when the input property is updated in subsequent deployments. The current input value is always available as an output property if you need to reference the updated value.

    Create a stash

    To create a new stash, instantiate a Stash resource and provide a value for the input property. The stash will store this value in your stack’s state and make it available through the output property.

    import * as pulumi from "@pulumi/pulumi";
    
    const myStash = new pulumi.Stash("myStash", {
        input: "Hello, World!",
    });
    
    export const stashedValue = myStash.output;
    
    import pulumi
    
    my_stash = pulumi.Stash("myStash", input="Hello, World!")
    
    pulumi.export("stashedValue", my_stash.output)
    
    package main
    
    import (
        "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
    )
    
    func main() {
        pulumi.Run(func(ctx *pulumi.Context) error {
            myStash, err := pulumi.NewStash(ctx, "myStash", &pulumi.StashArgs{
                Input: pulumi.String("Hello, World!"),
            })
            if err != nil {
                return err
            }
    
            ctx.Export("stashedValue", myStash.Output)
            return nil
        })
    }
    
    using Pulumi;
    
    return await Deployment.RunAsync(() =>
    {
        var myStash = new Stash("myStash", new StashArgs
        {
            Input = "Hello, World!",
        });
    
        return new Dictionary<string, object?>
        {
            ["stashedValue"] = myStash.Output,
        };
    });
    
    package myproject;
    
    import com.pulumi.Pulumi;
    import com.pulumi.core.Output;
    import com.pulumi.resources.Stash;
    import com.pulumi.resources.StashArgs;
    
    public class App {
        public static void main(String[] args) {
            Pulumi.run(ctx -> {
                var myStash = new Stash("myStash", StashArgs.builder()
                    .input("Hello, World!")
                    .build());
    
                ctx.export("stashedValue", myStash.output());
            });
        }
    }
    
    resources:
      myStash:
        type: pulumi:pulumi:Stash
        properties:
          input: "Hello, World!"
    
    outputs:
      stashedValue: ${myStash.output}
    

    Stash is like any other resource in that its name must be unique across the whole program.

    Stashing complex values

    The input property of a Stash resource can accept any value, including complex objects, arrays, and nested structures. The value will be serialized as a Pulumi property value when stored in state.

    const configStash = new pulumi.Stash("configStash", {
        input: {
            region: "us-west-2",
            instanceType: "t3.micro",
            tags: {
                Environment: "production",
                Team: "platform",
            },
        },
    });
    
    config_stash = pulumi.Stash("configStash", input={
        "region": "us-west-2",
        "instanceType": "t3.micro",
        "tags": {
            "Environment": "production",
            "Team": "platform",
        },
    })
    
    configStash, err := pulumi.NewStash(ctx, "configStash", &pulumi.StashArgs{
        Input: pulumi.Map{
            "region":       pulumi.String("us-west-2"),
            "instanceType": pulumi.String("t3.micro"),
            "tags": pulumi.Map{
                "Environment": pulumi.String("production"),
                "Team":        pulumi.String("platform"),
            },
        },
    })
    
    var configStash = new Stash("configStash", new StashArgs
    {
        Input = new Dictionary<string, object>
        {
            ["region"] = "us-west-2",
            ["instanceType"] = "t3.micro",
            ["tags"] = new Dictionary<string, object>
            {
                ["Environment"] = "production",
                ["Team"] = "platform",
            },
        },
    });
    
    var configStash = new Stash("configStash", StashArgs.builder()
        .input(Map.of(
            "region", "us-west-2",
            "instanceType", "t3.micro",
            "tags", Map.of(
                "Environment", "production",
                "Team", "platform"
            )
        ))
        .build());
    
    resources:
      configStash:
        type: pulumi:pulumi:Stash
        properties:
          input:
            region: us-west-2
            instanceType: t3.micro
            tags:
              Environment: production
              Team: platform
    

    Stashing secret values

    The Stash resource respects secret annotations. If the input value is marked as a secret, the output will also be secret, and the value will be encrypted in your stack’s state.

    const apiKeyStash = new pulumi.Stash("apiKeyStash", {
        input: pulumi.secret("my-secret-api-key"),
    });
    
    // The output is also marked as secret
    export const apiKey = apiKeyStash.output;
    
    api_key_stash = pulumi.Stash("apiKeyStash",
        input=pulumi.Output.secret("my-secret-api-key"))
    
    # The output is also marked as secret
    pulumi.export("apiKey", api_key_stash.output)
    
    apiKeyStash, err := pulumi.NewStash(ctx, "apiKeyStash", &pulumi.StashArgs{
        Input: pulumi.ToSecret(pulumi.String("my-secret-api-key")),
    })
    if err != nil {
        return err
    }
    
    // The output is also marked as secret
    ctx.Export("apiKey", apiKeyStash.Output)
    
    var apiKeyStash = new Stash("apiKeyStash", new StashArgs
    {
        Input = Output.CreateSecret("my-secret-api-key"),
    });
    
    // The output is also marked as secret
    return new Dictionary<string, object?>
    {
        ["apiKey"] = apiKeyStash.Output,
    };
    
    var apiKeyStash = new Stash("apiKeyStash", StashArgs.builder()
        .input(Output.secret("my-secret-api-key"))
        .build());
    
    // The output is also marked as secret
    ctx.export("apiKey", apiKeyStash.output());
    
    resources:
      apiKeyStash:
        type: pulumi:pulumi:Stash
        properties:
          input:
            fn::secret: my-secret-api-key
    
    outputs:
      apiKey: ${apiKeyStash.output}
    

    When viewing stashed secret values, their plaintext content will not be shown by default. Instead, they will be displayed as [secret] in the CLI. Pass --show-secrets to the command run to reveal the plaintext value.

    Updating stashed values

    To update the value stored in a Stash you need to replace it. There are a few ways to do this.

    1. Using the --target-replace argument to up to tell the engine to replace it.
    2. Using pulumi state taint to mark the resource to be replaced on the next deployment.
    3. Using the TriggerReplacement resource option to trigger the resource to replace on a change of value.

    Without a replacement, any changes to the input property will be reflected in the input output property, but the output property will not change. It will continue to return the original value the Stash was constructed with.

    Deleting a stash

    To delete a Stash resource, remove it from your program and run pulumi up. Pulumi will remove the stash from your stack’s state during the update.

    Common use cases

    The Stash resource is useful for keeping track of a computed value across deployments. Examples include things like the first user running the deployment, the first time the stack was created, a generated random value that needs to be stable.

    Capturing the first deployment user

    When you need to record who first deployed the infrastructure:

    import * as pulumi from "@pulumi/pulumi";
    import * as os from "os";
    
    const firstDeployer = new pulumi.Stash("firstDeployer", {
        input: os.userInfo().username,
    });
    
    // The output will always show the original deployer, even if others run updates later
    export const originalDeployer = firstDeployer.output;
    
    import pulumi
    import getpass
    
    first_deployer = pulumi.Stash("firstDeployer",
        input=getpass.getuser())
    
    # The output will always show the original deployer, even if others run updates later
    pulumi.export("originalDeployer", first_deployer.output)
    
    import (
        "os"
        "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
    )
    
    func main() {
        pulumi.Run(func(ctx *pulumi.Context) error {
            firstDeployer, err := pulumi.NewStash(ctx, "firstDeployer", &pulumi.StashArgs{
                Input: pulumi.String(os.Getenv("USER")),
            })
            if err != nil {
                return err
            }
    
            // The output will always show the original deployer, even if others run updates later
            ctx.Export("originalDeployer", firstDeployer.Output)
            return nil
        })
    }
    
    using Pulumi;
    using System;
    
    return await Deployment.RunAsync(() =>
    {
        var firstDeployer = new Stash("firstDeployer", new StashArgs
        {
            Input = Environment.UserName,
        });
    
        // The output will always show the original deployer, even if others run updates later
        return new Dictionary<string, object?>
        {
            ["originalDeployer"] = firstDeployer.Output,
        };
    });
    
    // Coming later
    

    Recording the initial creation time

    When you need to persist the timestamp of when the infrastructure was first created:

    import * as pulumi from "@pulumi/pulumi";
    
    const creationTime = new pulumi.Stash("creationTime", {
        input: new Date().toISOString(),
    });
    
    // This will always return the original creation time
    export const firstDeployed = creationTime.output;
    
    import pulumi
    from datetime import datetime
    
    creation_time = pulumi.Stash("creationTime",
        input=datetime.now().isoformat())
    
    # This will always return the original creation time
    pulumi.export("firstDeployed", creation_time.output)
    
    import (
        "time"
        "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
    )
    
    func main() {
        pulumi.Run(func(ctx *pulumi.Context) error {
            creationTime, err := pulumi.NewStash(ctx, "creationTime", &pulumi.StashArgs{
                Input: pulumi.String(time.Now().Format(time.RFC3339)),
            })
            if err != nil {
                return err
            }
    
            // This will always return the original creation time
            ctx.Export("firstDeployed", creationTime.Output)
            return nil
        })
    }
    
    using Pulumi;
    using System;
    
    return await Deployment.RunAsync(() =>
    {
        var creationTime = new Stash("creationTime", new StashArgs
        {
            Input = DateTime.UtcNow.ToString("o"),
        });
    
        // This will always return the original creation time
        return new Dictionary<string, object?>
        {
            ["firstDeployed"] = creationTime.Output,
        };
    });
    
    // Coming later
    

    Preserving a stable random value

    When you need a random value that remains constant across deployments:

    import * as pulumi from "@pulumi/pulumi";
    import * as random from "@pulumi/random";
    
    // Generate a random password once
    const randomPassword = generatePassword()
    
    // Stash it so it doesn't change on subsequent deployments
    const passwordStash = new pulumi.Stash("passwordStash", {
        input: pulumi.secret(randomPassword.result),
    });
    
    // Use the stashed password for database configuration
    export const dbPassword = passwordStash.output;
    
    import pulumi
    import pulumi_random as random
    
    # Generate a random password once
    random_password = generatePassword()
    
    # Stash it so it doesn't change on subsequent deployments
    password_stash = pulumi.Stash("passwordStash",
        input=pulumi.Output.secret(random_password.result))
    
    # Use the stashed password for database configuration
    pulumi.export("dbPassword", password_stash.output)
    
    import (
        "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
        "github.com/pulumi/pulumi-random/sdk/v4/go/random"
    )
    
    func main() {
        pulumi.Run(func(ctx *pulumi.Context) error {
            // Generate a random password once
            randomPassword, err := generatePassword()
            if err != nil {
                return err
            }
    
            // Stash it so it doesn't change on subsequent deployments
            passwordStash, err := pulumi.NewStash(ctx, "passwordStash", &pulumi.StashArgs{
                Input: pulumi.ToSecret(randomPassword.Result),
            })
            if err != nil {
                return err
            }
    
            // Use the stashed password for database configuration
            ctx.Export("dbPassword", passwordStash.Output)
            return nil
        })
    }
    
    using Pulumi;
    using Pulumi.Random;
    
    return await Deployment.RunAsync(() =>
    {
        // Generate a random password once
        var randomPassword = generatePassword();
    
        // Stash it so it doesn't change on subsequent deployments
        var passwordStash = new Stash("passwordStash", new StashArgs
        {
            Input = Output.CreateSecret(randomPassword.Result),
        });
    
        // Use the stashed password for database configuration
        return new Dictionary<string, object?>
        {
            ["dbPassword"] = passwordStash.Output,
        };
    });
    
    // Coming later
    
      Neo just got smarter about infrastructure policy automation