Skip to main content
  1. Docs
  2. Deployments & Workflows
  3. Deployments
  4. Runs
  5. Images

Images

    Pulumi Cloud runs your Pulumi program inside a container image called the deployment executor image. This page covers what is in that image and how to customize it.

    The default executor image

    By default, every deployment runs in pulumi/pulumi, a Linux image that includes:

    • The pulumi CLI on $PATH
    • LTS versions of all supported language runtimes: Node.js, Python, Go, .NET, and Java
    • Common build tools: git, curl, and the package manager for each runtime

    For most projects this is the right choice. The image is updated with every Pulumi CLI release, security-patched on a regular cadence, and pre-cached on Pulumi-hosted workflow runners, so deployments start quickly without paying a registry pull.

    The image is published in pulumi/pulumi-docker-containers. That repository also publishes smaller variants you can use as a base for a custom image. See Choosing a base image below.

    When to customize

    You need a different setup when your deployment depends on something not in the default image. Common cases:

    • A CLI such as gh or aws that your Pulumi program or a deployment hook invokes
    • A language runtime version different from the LTS in the default image
    • A system package required by a native dependency
    • A private credential helper

    There are two ways to handle this. Pick based on how often you need the tool and how much you care about deployment speed.

    Choosing the right approach

    ApproachBest forCost
    Pre-run commandsOne-off tools, scripts, or quick experimentsThe install runs on every deployment, adding setup time to each run
    Custom executor imageStable tool sets used on every deploymentSlower cold starts on fresh runners, and an image you have to maintain

    Pre-run commands

    If you need a tool occasionally, or you are still prototyping, install it from a pre-run command in your deployment settings:

    apt-get update && apt-get install -y my-tool
    

    Pros:

    • No image to build or maintain
    • Easy to change: edit the command and the next deployment picks it up
    • Works with the default pulumi/pulumi image, so cold starts stay fast

    Cons:

    • The install runs on every deployment, adding wall-clock time
    • Network failures during the install fail the deployment
    • Not suitable for very large installs

    Reach for a custom image only when the install cost starts to hurt.

    Custom executor image

    A custom executor image is a container image you build, host, and reference from your stack’s deployment settings. Pulumi pulls it before running each deployment.

    Choosing a base image

    Pick the smallest base that has the language runtime(s) you need. Pull time scales with image size, so a smaller base means faster first deployments on fresh runners.

    Base imageSize (approx.)ContentsBest for
    pulumi/pulumi-base~200 MBpulumi CLI onlyYou will install your own language runtime, or use a single language version not in the SDK images
    pulumi/pulumi-nodejs, pulumi-python, pulumi-go, pulumi-dotnet, pulumi-java200–400 MBpulumi plus one language runtimeSingle-language projects
    pulumi/pulumi~2 GBpulumi plus all language runtimesPolyglot projects, or when you do not want to pick a runtime

    If you do not need every language runtime, start from pulumi/pulumi-base or a language-specific variant. The full pulumi/pulumi image is convenient but copies ~2 GB of layers your project will not use.

    All variants are listed in the pulumi/pulumi-docker-containers README.

    Example: adding the GitHub CLI

    # Pin the Pulumi CLI version explicitly. Floating tags like :latest mean the
    # image and your local CLI can drift apart between deployments.
    FROM pulumi/pulumi-base:3.236.0
    
    RUN apt-get update \
        && apt-get install -y --no-install-recommends gh \
        && rm -rf /var/lib/apt/lists/*
    

    Build, push to a registry your deployment runner can reach, then point your stack at it from the Custom Executor Image setting or the executorContext.executorImage field of the REST API.

    Image requirements

    A custom executor image must:

    • Be a Linux image
    • Include curl on $PATH
    • Include the pulumi CLI on $PATH
    • Include the language runtime(s) for the projects that will use it
    • Use a glibc-based libc. Most Pulumi resource provider plugins are glibc-linked, so musl-only images such as Alpine are not supported

    If you start from one of the pulumi/* base images, all of these are already true.

    Trade-offs

    Cold starts

    The default image is pre-cached on Pulumi-hosted workflow runners. Custom images are not. Every newly-provisioned runner pulls your image from its registry the first time it runs your deployment, which can add minutes to the “Preparing environment” phase.

    To reduce cold-start time:

    • Start from a small base (pulumi-base or a single-language variant)
    • Host the image close to the runner. Pulumi-hosted runners run in AWS us-west-2, so an image in a us-west-2 ECR is faster than one on Docker Hub.
    • Pin a digest so the runner can rely on its layer cache between deployments instead of re-fetching by tag.

    Static credentials only

    If your image lives in a private registry, you must supply static username and password credentials in the deployment settings. OIDC and IAM-role-based pulls are not supported for custom executor images. If your security model requires short-lived registry credentials, Customer-Managed Workflow Runners run in your own infrastructure and can use whatever pull mechanism you configure.

    See also