Skip to main content
Pulumi logo Pulumi logo
  1. Docs
  2. Infrastructure as Code
  3. Concepts
  4. Configuration

Configuration

    Different stacks for a single project often need different values. You might want a different size for your AWS EC2 instance, or a different number of servers for your Kubernetes cluster, between your development and production stacks.

    Pulumi offers a configuration system for managing such differences. Instead of hard-coding the differences, you can store and retrieve configuration values using a combination of the CLI and the programming model.

    The key-value pairs for any given stack are stored in your project’s stack settings file, which is automatically named Pulumi.<stack-name>.yaml. Stack configuration files should be committed to version control because their values drive the behavior of your Pulumi program.

    Configuration options

    You can use both the CLI and the programming model for your Pulumi configuration.

    • The CLI offers a config command with set and get subcommands for managing key-value pairs.
    • The programming model offers a Config object with getters for retrieving values.
    All shell environment variables are passed to the running program and can be read with standard runtime APIs, such as process.env in Node.js and os.environ in Python, which can also drive dynamic behavior. Prefer configuration, however, because it’s designed for multi-stack collaborative scenarios.

    Configuration keys

    Configuration keys use the format [<namespace>:]<key-name>, with a colon delimiting the optional namespace and the actual key name. When a key name is used without a colon, Pulumi uses the current project name from Pulumi.yaml as the namespace.

    This namespacing allows the AWS package to accept a configuration value for aws:region without conflicting with other packages using the common key name region. It also allows custom components to define their own key spaces without risk of conflicting with other components, packages, or projects.

    Setting and getting configuration values

    The pulumi config CLI command can get, set, or list configuration key-value pairs in your current project stack:

    • pulumi config set <key> [value] sets a configuration entry <key> to [value].
    • pulumi config get <key> gets an existing configuration value with the key <key>.
    • pulumi config gets all configuration key-value pairs in the current stack (as JSON if --json is passed).
    When using the config set command, any existing value for <key> is overwritten without warning.

    For example, to set and then get the current AWS region in the aws package, run the following:

    $ pulumi config set aws:region us-west-2
    $ pulumi config get aws:region
    us-west-2
    

    To set and get configuration in the current project (named broome-proj, for example), use the key name on its own:

    $ pulumi config set name BroomeLLC
    $ pulumi config get name
    BroomeLLC
    

    If you omit [value] when setting a configuration key, the CLI prompts for it interactively. You can also pipe the value in on standard input, which helps with multiline values or any value that would otherwise need escaping on the command line:

    $ cat my_key.pub | pulumi config set publicKey
    

    Using the config flag with pulumi new

    Configuration keys and values can be passed when using pulumi new.

    To pass a single key/value config pair use:

    $ pulumi new template-name --config="key=value"
    

    To pass multiple key/value config pairs use:

    $ pulumi new template-name --config="key=value" --config="key=value"
    

    And a complete example showing how to pass in the AWS region:

    $ pulumi new aws-typescript --config="aws:region=us-west-2"
    

    Accessing configuration from code

    Configuration values can be retrieved for a given stack using either Config.get Config.get Config.get config.Get Config.Get or Config.require Config.require Config.require config.Require Config.Require . Config.get Config.get Config.get config.Get Config.Get returns undefined undefined None nil null if the configuration value was not provided, and Config.require Config.require Config.require config.Require Config.Require raises an exception with an explanatory error message, stopping the deployment until the value is set with the CLI.

    Configuration values can only be read during program execution, not set. To programmatically manage stack configurations (like setting config values or creating stacks dynamically), use Automation API. Automation API provides full programmatic control over Pulumi operations, including writing configuration values to stack files and managing stack lifecycle.

    For potentially secret config, use Config.getSecret Config.getSecret Config.get_secret config.GetSecret Config.GetSecret ctx.config().getSecret(key) or Config.requireSecret Config.requireSecret Config.require_secret config.RequireSecret Config.RequireSecret ctx.config().requireSecret(key) , which return the config value as an Output that carries both the value and its secret-ness, so the value is encrypted whenever it’s serialized (see secrets for more on managing secret values).

    Configuration methods operate on a particular namespace, which by default is the name of the current project. Passing an empty constructor to Config Config Config config Config , as in the following example, sets it up to read values set without an explicit namespace (e.g., pulumi config set name Joe):

    let config = new pulumi.Config();
    let name = config.require("name");
    let lucky = config.getNumber("lucky") || 42;
    let secret = config.requireSecret("secret");
    
    config = pulumi.Config()
    name = config.require('name')
    lucky = config.get_int('lucky') or 42
    secret = config.require_secret('secret')
    
    package main
    
    import (
        "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
        "github.com/pulumi/pulumi/sdk/v3/go/pulumi/config"
    )
    func main() {
        pulumi.Run(func(ctx *pulumi.Context) error {
            conf := config.New(ctx, "")
            name := conf.Require("name")
            lucky, err := conf.TryInt("lucky")
            if err != nil {
                lucky = 42
            }
            secret := conf.RequireSecret("secret")
            ctx.Export("name", pulumi.String(name))
            ctx.Export("lucky", pulumi.Int(lucky))
            ctx.Export("secret", secret)
            return nil
        })
    }
    
    var config = new Pulumi.Config();
    var name = config.Require("name");
    var lucky = config.GetInt32("lucky") ?? 42;
    var secret = config.RequireSecret("secret");
    
    public static void stack(Context ctx) {
        var config = ctx.config();
        var name = config.require("name");
        var lucky = config.getInteger("lucky").orElse(42);
        var secret = config.requireSecret("secret");
    }
    
    config:
      name:
        type: string
      lucky:
        default: 42
      secret:
        type: string
        secret: true
    

    To access a namespaced configuration value, such as one set for a provider library like aws, you must pass the library’s name to the constructor. The examples below assume the value has already been set in your stack’s configuration file (e.g., Pulumi.dev.yaml) — either by running pulumi config set aws:region us-west-2 from the command line, or by adding it to the file directly:

    # Pulumi.dev.yaml
    config:
      aws:region: us-west-2
    

    Given that configuration, the following shows how to read the value from within your Pulumi program:

    let awsConfig = new pulumi.Config("aws");
    let awsRegion = awsConfig.require("region");
    
    aws_config = pulumi.Config("aws")
    aws_region = aws_config.require("region")
    
    awsConfig := config.New(ctx, "aws")
    awsRegion := awsConfig.Require("region")
    
    var awsConfig = new Pulumi.Config("aws");
    var awsRegion = awsConfig.Require("region");
    
    var awsConfig = ctx.config("aws");
    var awsRegion = awsConfig.require("region");
    
    variables:
      awsRegion: ${aws:region}
    

    Similarly, if you are writing code that will be imported into a broader project, such as your own library of Pulumi components, pass your library’s name to the Config Config Config config Config constructor to limit the scope of the query to values prefixed with the name of your library:

    class MyComponent extends pulumi.ComponentResource {
        constructor(name: string, args = {}, opts: pulumi.ComponentResourceOptions = {}) {
            super("mylib:index:MyComponent", name, args, opts);
    
            // Read settings from the 'mylib' namespace (e.g., 'mylib:name').
            const config = new pulumi.Config("mylib");
            const configuredName = config.require("name");
        }
    }
    
    class MyComponent(pulumi.ComponentResource):
        def __init__(self, name, opts = None):
            super().__init__("mylib:index:MyComponent", name, None, opts)
    
            # Read settings from the 'mylib' namespace (e.g., 'mylib:name').
            config = pulumi.Config("mylib")
            configured_name = config.require("name")
    
            # ...
    
    type MyComponent struct {
        pulumi.ResourceState
    }
    
    func NewMyComponent(ctx *pulumi.Context, name string, opts ...pulumi.ResourceOption) (*MyComponent, error) {
        myComponent := &MyComponent{}
        err := ctx.RegisterComponentResource("mylib:index:MyComponent", name, myComponent, opts...)
        if err != nil {
            return nil, err
        }
    
        // Read settings from the 'mylib' namespace (e.g., 'mylib:name').
        conf := config.New(ctx, "mylib")
        configuredName := conf.Require("name")
    
        // ...
    }
    
    class MyComponent : Pulumi.ComponentResource
    {
        public MyComponent(string name, ComponentResourceOptions opts)
            : base("mylib:index:MyComponent", name, opts)
        {
    
            // Read settings from the 'mylib' namespace (e.g., 'mylib:name').
            var config = new Pulumi.Config("mylib");
            var configuredName = config.Require("name");
    
            // ...
        }
    }
    
    import com.pulumi.resources.ComponentResource;
    import com.pulumi.resources.ComponentResourceOptions;
    
    class MyComponent extends ComponentResource {
        public MyComponent(String name, ComponentResourceOptions opts) {
            super("mylib:index:MyComponent", name, null, opts);
    
            // Read settings from the 'mylib' namespace (e.g., 'mylib:name').
            var config = ctx.config("mylib");
            var configuredName = config.require("name");
    
            // ...
        }
    }
    

    Structured configuration

    Pulumi also supports structured configuration, which you set with pulumi config set and the --path flag. --path tells the CLI to treat the config key as a path to a location within an object.

    For example:

    $ pulumi config set --path 'data.active' true
    $ pulumi config set --path 'data.nums[0]' 1
    $ pulumi config set --path 'data.nums[1]' 2
    $ pulumi config set --path 'data.nums[2]' 3
    

    The structure of data is persisted in the stack’s Pulumi.<stack-name>.yaml file. Note the types: true and false are persisted as boolean values, and values convertible to integers are persisted as integers.

    config:
      proj:data:
        active: true
        nums:
        - 1
        - 2
        - 3
    

    The data config can be accessed in your Pulumi program using:

    interface Data {
        active: boolean;
        nums: number[];
    }
    
    let config = new pulumi.Config();
    let data = config.requireObject<Data>("data");
    console.log(`Active: ${data.active}`);
    
    config = pulumi.Config()
    data = config.require_object("data")
    print("Active:", data.get("active"))
    
    package main
    
    import (
        "fmt"
    
        "github.com/pulumi/pulumi/sdk/v3/go/pulumi"
        "github.com/pulumi/pulumi/sdk/v3/go/pulumi/config"
    )
    
    type Data struct {
        Active bool
        Nums   []int
    }
    
    func main() {
        pulumi.Run(func(ctx *pulumi.Context) error {
            var d Data
            cfg := config.New(ctx, "")
            cfg.RequireObject("data", &d)
            fmt.Printf("Active: %v\n", d.Active)
            return nil
        })
    }
    
    var config = new Pulumi.Config();
    var data = config.RequireObject<JsonElement>("data");
    Console.WriteLine($"Active: {data.GetProperty("active")}");
    
    public static void stack(Context ctx) {
        var config = ctx.config();
        var data = config.requireObject("data", Map.class);
        ctx.log().info(String.format("Active: %s", data.get("active")));
    }
    

    In Pulumi YAML, you declare the config inputs your program accepts using the config block in your Pulumi.yaml file. To work with structured (object) configuration, declare the key with type: Object. Pass the value from the stack configuration file using pulumi config set --path, and reference the whole object or individual properties in your program using ${configKey} interpolation.

    name: my-project
    runtime: yaml
    config:
      data:
        type: Object
        default:
          active: true
          nums:
            - 1
            - 2
            - 3
    resources:
      my-bucket:
        type: aws:s3:BucketV2
        properties:
          tags:
            Active: ${data.active}
    

    Accessing nested values

    requireObject and getObject return a plain object — a dictionary or map, depending on the language — and not a Config instance. Once you have the object, reach into it with ordinary property or key access rather than chaining more Config calls. Nesting can go deeper than one level, as in this api key:

    $ pulumi config set --path 'api.endpoint' "https://api.example.com"
    $ pulumi config set --path 'api.timeout' 30
    $ pulumi config set --path 'api.headers.authorization' "Bearer token123"
    $ pulumi config set --path 'api.headers.content-type' "application/json"
    

    Read the whole api object once, then walk it:

    interface ApiConfig {
        endpoint: string;
        timeout: number;
        headers: {
            authorization: string;
            "content-type": string;
        };
    }
    
    const config = new pulumi.Config();
    const apiConfig = config.requireObject<ApiConfig>("api");
    
    // Access nested properties directly using standard object notation
    const endpoint = apiConfig.endpoint;  // "https://api.example.com"
    const timeout = apiConfig.timeout;    // 30
    const authHeader = apiConfig.headers.authorization;  // "Bearer token123"
    
    // You CANNOT chain config.require() calls like this:
    // const endpoint = config.require("api").require("endpoint");  // This does NOT work!
    // Reason: requireObject() returns a plain JavaScript object, not a Config instance,
    // and only Config instances have the require() method.
    
    config = pulumi.Config()
    api_config = config.require_object("api")
    
    # Access nested properties using dictionary notation
    endpoint = api_config["endpoint"]  # "https://api.example.com"
    timeout = api_config["timeout"]    # 30
    auth_header = api_config["headers"]["authorization"]  # "Bearer token123"
    
    type ApiConfig struct {
        Endpoint string
        Timeout  int
        Headers  map[string]string
    }
    
    cfg := config.New(ctx, "")
    var apiConfig ApiConfig
    cfg.RequireObject("api", &apiConfig)
    
    // Access nested properties directly
    endpoint := apiConfig.Endpoint  // "https://api.example.com"
    timeout := apiConfig.Timeout    // 30
    authHeader := apiConfig.Headers["authorization"]  // "Bearer token123"
    
    var config = new Pulumi.Config();
    var apiConfig = config.RequireObject<JsonElement>("api");
    
    // Access nested properties
    var endpoint = apiConfig.GetProperty("endpoint").GetString();  // "https://api.example.com"
    var timeout = apiConfig.GetProperty("timeout").GetInt32();    // 30
    var authHeader = apiConfig.GetProperty("headers")
        .GetProperty("authorization").GetString();  // "Bearer token123"
    
    var config = ctx.config();
    var apiConfig = config.requireObject("api", Map.class);
    
    // Access nested properties
    var endpoint = (String) apiConfig.get("endpoint");  // "https://api.example.com"
    var timeout = (Integer) apiConfig.get("timeout");   // 30
    var headers = (Map<String, String>) apiConfig.get("headers");
    var authHeader = headers.get("authorization");  // "Bearer token123"
    

    In Pulumi YAML, declare the object config input in your Pulumi.yaml file, then reference its properties using dot notation in interpolation expressions.

    name: my-project
    runtime: yaml
    config:
      api:
        type: Object
        default:
          endpoint: https://api.example.com
          timeout: 30
          headers:
            authorization: Bearer token123
            content-type: application/json
    outputs:
      # Access nested properties using dot notation in interpolation expressions
      endpoint: ${api.endpoint}
      timeout: ${api.timeout}
      authHeader: ${api.headers.authorization}
    

    Project-level configuration

    Some configuration is the same for more than one stack in a project — aws:region, for example, is often shared by every stack in the project. Project-level configuration (also called hierarchical configuration) lets you set such values once at the project level instead of repeating them in every stack’s configuration file.

    Setting project-level configuration

    You define project-level configuration in the project folder’s Pulumi.yaml file, using any text editor.

    The pulumi config set command does not currently support project-level configuration. Enter the configuration values directly in the Pulumi.yaml file instead. Project-level configuration also supports plaintext values only. Support for setting project-level config from the CLI, project-level secrets, and other features is planned.

    Project-level configuration supports both flat and structured configuration, in the same forms described in Structured configuration.

    Important: Stack-level and project-level YAML files use different syntax for structured configuration:

    • Stack-level files (Pulumi.<stack-name>.yaml): use the format projectname:key:, and nest structured values directly under the key.
    • Project-level file (Pulumi.yaml): use the format key: with no project name prefix, and nest structured values under a value: wrapper.

    Watch for this difference when you move configuration between the two files.

    Using the keys from the earlier examples, and applying the value: wrapper that project-level structured config requires, project-level configuration inside Pulumi.yaml looks like this:

    config:
      aws:region: us-east-1
      name: BroomeLLC
      data:
        value: # Required for project-level structured config
          active: true
          nums:
          - 10
          - 20
          - 30
    

    The same configuration in a stack-level file (Pulumi.dev.yaml) would look like this (assuming your project name is myproject):

    config:
      aws:region: us-east-1
      myproject:name: BroomeLLC
      myproject:data:             # Note: uses project name prefix and no 'value' key needed
        active: true
        nums:
        - 10
        - 20
        - 30
    

    With project-level configuration in place, every stack in the project uses those values by default, unless a stack’s own configuration overrides them.

    Project and stack configuration scope

    Stack-level configuration using the same key supersedes the project-level configuration for that key. For example, given the project-level configuration above and a Pulumi.dev.yaml file containing:

    config:
      aws:region: us-east-2
      name: MopLLC
    

    Then the dev stack would be deployed in us-east-2 instead of us-east-1 and the name configuration value would be MopLLC instead of BroomeLLC defined in the project configuration.

    Strongly typed configuration

    Project-level configuration can also define type specifications for stack-level configuration, including defaults. Commands like pulumi preview then fail with an error if a stack-level configuration value has the wrong type.

    For example, given this in the Pulumi.yaml file:

    config:
      name:
        type: string
        description: Base name to use for resources.
        default: BroomeLLC
      subnets:
        type: array
        description: Array of subnets to create.
        items:
          type: string
    

    Stacks default to BroomeLLC for the name configuration item, and the Pulumi CLI reports an error if a stack configuration file sets name to, say, an integer. The CLI reports an error in the same way if a stack’s subnets property is not an array of strings.

    At this time, configuration specifications are not supported for structured configuration.

    Provider configuration options

    You can configure providers in three ways:

    1. Set configuration keys in the stack configuration file: pulumi config set [PROVIDER]:[KEY] [VALUE]
    2. Set a provider-specific environment variable
    3. Pass arguments to the provider’s SDK constructor, in your program

    Note the following:

    • Only the default provider reads configuration file settings. A provider object that you instantiate yourself does not read values from the stack configuration.
    • The precedence of configuration sources (configuration file, environment, and constructor arguments) can vary between providers. Refer to the provider’s documentation for its specific rules.
    • Default providers can be turned off for some or all packages with the pulumi:disable-default-providers key, described below.

    Pulumi configuration options

    This is a list of configuration keys that the Pulumi CLI is aware of:

    pulumi:disable-default-providers

    A list of packages for which default providers should be disabled. * disables default providers for all packages.

    In the following example, the default providers for aws and kubernetes are disabled.

    config:
      pulumi:disable-default-providers:
        - aws
        - kubernetes
    

    pulumi:tags

    A list of stack tags which are read by the Pulumi CLI and automatically applied on the stack at every pulumi up or pulumi refresh action.

    config:
      pulumi:tags:
        company: "Some LLC"
        team: Ops
    

    The Pulumi CLI only creates or updates tags listed in the config. If you remove a tag from the stack config, remove it from the stack in Pulumi Cloud manually as well.

    Stack tags applied by the Pulumi CLI are listed in the Tags section of the Overview tab:

    Tags applied by the Pulumi CLI

    Using Pulumi ESC from Pulumi stack config

    This Pulumi Cloud feature is available in all editions.

    Configuration and secrets that several stacks share don’t have to be duplicated across their stack configuration files — Pulumi ESC can hold them centrally instead.

    Once you have an environment set up and are projecting Pulumi configuration from it, you can import that environment (or several environments) into your Pulumi stack.

    # import the test environment and all of its configuration
    environment:
      - test
    config:
      # normal pulumi config
    

    When a key is set both by an imported environment and explicitly in your stack configuration, the explicit stack value takes precedence. See Precedence for the full rules.

      The infrastructure as code platform for any cloud.