---
title: Automation API
url: /docs/iac/guides/building-extending/automation-api/
---
The Pulumi [Automation API](/docs/iac/concepts/automation-api/) lets you provision infrastructure programmatically by driving the Pulumi engine from your own code, exposing Pulumi programs and stacks as strongly typed, composable building blocks.

In this guide, you'll deploy an inline Pulumi program that creates a static website with Automation API. For background on workspaces, stacks, and inline versus local programs, see [Automation API concepts](/docs/iac/concepts/automation-api/).

## Prerequisites

Before you begin, make sure you have:

- The [Pulumi CLI](/docs/install/) installed and available on your `PATH`. Automation API drives the CLI under the hood. Or, your program can [install the CLI programmatically](#install-the-cli-programmatically) at runtime.
- The runtime for your chosen language installed: Node.js, Python, Go, .NET, or Java.
- A [Pulumi access token](/docs/administration/access-identity/access-tokens/) so your program can store state in Pulumi Cloud. Run `pulumi login` to authenticate, or set the `PULUMI_ACCESS_TOKEN` environment variable.
- AWS credentials configured, since this guide deploys resources to AWS.

### Install the CLI programmatically

Because Automation API runs the Pulumi CLI for you, the CLI must be available at runtime. Rather than requiring everyone who runs your program to install it themselves, you can have the program download and manage its own copy. The TypeScript, Python, Go, and .NET SDKs expose an install method that downloads a specific CLI version---by default, the version matching the SDK---into `~/.pulumi/versions/<version>`. You then pass the resulting command object to the workspace that runs your stack.

<!-- chooser: language -->

<!-- option: typescript -->
```typescript
import { LocalWorkspace, PulumiCommand } from "@pulumi/pulumi/automation";

// Install the CLI version matching the SDK into ~/.pulumi/versions/<version>.
const pulumiCommand = await PulumiCommand.install();

```

Pass it to the workspace through the `pulumiCommand` option when you create the stack:
```typescript
const stack = await LocalWorkspace.createOrSelectStack(args, { pulumiCommand });

```

<!-- /option -->

<!-- option: python -->
```python
from pulumi import automation as auto

# Install the CLI version matching the SDK into ~/.pulumi/versions/<version>.
pulumi_command = auto.PulumiCommand.install()

```

Pass it to the workspace through the `pulumi_command` option when you create the stack:
```python
stack = auto.create_or_select_stack(stack_name=stack_name,
                                    project_name=project_name,
                                    program=pulumi_program,
                                    opts=auto.LocalWorkspaceOptions(pulumi_command=pulumi_command))

```

<!-- /option -->

<!-- option: go -->
```go
import "github.com/pulumi/pulumi/sdk/v3/go/auto"

ctx := context.Background()

// Install the CLI version matching the SDK into ~/.pulumi/versions/<version>.
pulumiCmd, err := auto.InstallPulumiCommand(ctx, &auto.PulumiCommandOptions{})
if err != nil {
    fmt.Printf("Failed to install the Pulumi CLI: %v\n", err)
    os.Exit(1)
}

```

Pass it to the workspace with the `auto.Pulumi` option when you create the stack:
```go
s, err := auto.UpsertStackInlineSource(ctx, stackName, projectName, deployFunc, auto.Pulumi(pulumiCmd))

```

<!-- /option -->

<!-- option: csharp -->
```csharp
using Pulumi.Automation;
using Pulumi.Automation.Commands;

// Install the CLI version matching the SDK into ~/.pulumi/versions/<version>.
var pulumiCommand = await LocalPulumiCommand.Install();

```

Pass it to the workspace through the `PulumiCommand` property when you create the stack:
```csharp
var stackArgs = new InlineProgramArgs(projectName, stackName, program)
{
    PulumiCommand = pulumiCommand,
};
var stack = await LocalWorkspace.CreateOrSelectStackAsync(stackArgs);

```

<!-- /option -->

<!-- option: java -->
The Java SDK doesn’t support installing the Pulumi CLI programmatically. Install the [Pulumi CLI](/docs/install/) manually and make sure it’s available on your `PATH`.

<!-- /option -->

<!-- /chooser -->

## Define your Pulumi program

<!-- chooser: language -->

First, define the Pulumi program you want to run as a function within your overall program. Note how it looks like a standard Pulumi program.

<!-- option: typescript -->

**Note:** This tutorial is based on the `inlineProgram-ts` example, which is a complete example of how to construct a simple Automation API program.

```typescript
const pulumiProgram = async () => {
    // Create a bucket and expose a website index document.
    const siteBucket = new s3.Bucket("s3-website-bucket", {});

    const indexContent = `<html><head>
<title>Hello S3</title><meta charset="UTF-8">
</head>
<body>Hello, world!Made with ❤️ with [Pulumi](https://pulumi.com)
</body></html>
`

    const ownershipControls = new aws.s3.BucketOwnershipControls("ownership-controls", {
        bucket: siteBucket.id,
        rule: {
            objectOwnership: "ObjectWriter",
        },
    });

    const publicAccessBlock = new aws.s3.BucketPublicAccessBlock("public-access-block", {
        bucket: siteBucket.id,
        blockPublicAcls: false,
    });

    const website = new aws.s3.BucketWebsiteConfigurationV2("website", {
        bucket: siteBucket.id,
        indexDocument: {
            suffix: "index.html",
        },
    });

    // Write our index.html into the site bucket.
    const object = new s3.BucketObject("index", {
        bucket: siteBucket.id,
        content: indexContent,
        contentType: "text/html; charset=utf-8",
        key: "index.html",
        acl: "public-read"
    }, {
        dependsOn: [publicAccessBlock,
            ownershipControls,
            website,
        ],
    });

    return {
        websiteUrl: website.websiteEndpoint,
    };
};

```

<!-- /option -->

<!-- option: python -->

**Note:** This tutorial is based on the `inline_program` example, which is a complete example of how to construct a simple Automation API program.

```python
def pulumi_program():
    # Create a bucket and expose a website index document.
    site_bucket = s3.Bucket("s3-website-bucket")

    index_content = """
    <html>
        <head><title>Hello S3</title><meta charset="UTF-8"></head>
        <body>
            Hello, world!
            Made with ❤️ with [Pulumi](https://pulumi.com)
        </body>
    </html>
    """

    ownership_controls = s3.BucketOwnershipControls("ownership-controls",
        bucket=site_bucket.id,
        rule={
            "object_ownership": "ObjectWriter",
        })

    public_access_block = s3.BucketPublicAccessBlock("public-access-block",
        bucket=site_bucket.id,
        block_public_acls=False)

    website = aws.s3.BucketWebsiteConfigurationV2("website",
        bucket=site_bucket.id,
        index_document={
            "suffix": "index.html",
        })

    # Write our index.html into the site bucket.
    s3.BucketObject("index",
                    bucket=site_bucket.id,  # Reference to the s3.Bucket object.
                    content=index_content,
                    acl="public-read",
                    key="index.html",  # Set the key of the object.
                    content_type="text/html; charset=utf-8", # Set the MIME type of the file.
                    opts=pulumi.ResourceOptions(depends_on=[public_access_block,
                        ownership_controls,
                        website,
                    ]))

    # Export the website URL.
    pulumi.export("website_url", website.website_endpoint)

```

<!-- /option -->

<!-- option: go -->

**Note:** This tutorial is based on the `inline_program` example, which is a complete example of how to construct a simple Automation API program.

```go
deployFunc := func(ctx *pulumi.Context) error {
    // Similar go git_repo_program, our program defines a s3 website.
    // Here we create the bucket.
    siteBucket, err := s3.NewBucket(ctx, "s3-website-bucket", nil)
    if err != nil {
        return err
    }

    // We define and upload our HTML inline.
    indexContent := `<html><head>
<title>Hello S3</title><meta charset="UTF-8">
</head>
<body>Hello, world!Made with ❤️ with [Pulumi](https://pulumi.com)
</body></html>
`

    ownershipControls, err := s3.NewBucketOwnershipControls(ctx, "ownership-controls", &s3.BucketOwnershipControlsArgs{
        Bucket: siteBucket.ID(),
        Rule: &s3.BucketOwnershipControlsRuleArgs{
            ObjectOwnership: pulumi.String("ObjectWriter"),
        },
    })
    if err != nil {
        return err
    }

    publicAccessBlock, err := s3.NewBucketPublicAccessBlock(ctx, "public-access-block", &s3.BucketPublicAccessBlockArgs{
        Bucket:          siteBucket.ID(),
        BlockPublicAcls: pulumi.Bool(false),
    })
    if err != nil {
        return err
    }

    website, err := s3.NewBucketWebsiteConfigurationV2(ctx, "website", &s3.BucketWebsiteConfigurationV2Args{
        Bucket: siteBucket.ID(),
        IndexDocument: &s3.BucketWebsiteConfigurationV2IndexDocumentArgs{
            Suffix: pulumi.String("index.html"),
        },
    })
    if err != nil {
        return err
    }
    // Upload our index.html.
    if _, err := s3.NewBucketObject(ctx, "index", &s3.BucketObjectArgs{
        Bucket:      siteBucket.ID(), // Reference to the s3.Bucket object.
        Content:     pulumi.String(indexContent),
        Acl:         pulumi.String("public-read"),
        Key:         pulumi.String("index.html"),               // Set the key of the object.
        ContentType: pulumi.String("text/html; charset=utf-8"), // Set the MIME type of the file.
    }, pulumi.DependsOn([]pulumi.Resource{
        publicAccessBlock,
        ownershipControls,
        website,
    })); err != nil {
        return err
    }

    // Export the website URL.
    ctx.Export("websiteUrl", website.WebsiteEndpoint)
    return nil
}

```

<!-- /option -->

<!-- option: csharp -->

**Note:** This tutorial is based on the `InlineProgram` example, which is a complete example of how to construct a simple Automation API program.

```csharp
var program = PulumiFn.Create(() =>
{
    // Create a bucket and expose a website index document.
    var siteBucket = new Pulumi.Aws.S3.Bucket("s3-website-bucket");

    const string indexContent = @"
<html>
    <head><title>Hello S3</title><meta charset=""UTF-8""></head>
    <body>
        Hello, world!
        Made with ❤️ with [Pulumi]()
    </body>
</html>";

    var ownershipControls = new Aws.S3.BucketOwnershipControls("ownership-controls", new()
    {
        Bucket = siteBucket.Id,
        Rule = new Aws.S3.Inputs.BucketOwnershipControlsRuleArgs
        {
            ObjectOwnership = "ObjectWriter",
        },
    });

    var publicAccessBlock = new Aws.S3.BucketPublicAccessBlock("public-access-block", new()
    {
        Bucket = siteBucket.Id,
        BlockPublicAcls = false,
    });

    var website = new Aws.S3.BucketWebsiteConfigurationV2("website", new()
    {
        Bucket = siteBucket.Id,
        IndexDocument = new Aws.S3.Inputs.BucketWebsiteConfigurationV2IndexDocumentArgs
        {
            Suffix = "index.html",
        },
    });

    // Write our index.html into the site bucket.
    var @object = new Pulumi.Aws.S3.BucketObject("index", new Pulumi.Aws.S3.BucketObjectArgs
    {
        Bucket = siteBucket.BucketName, // Reference to the s3 bucket object.
        Content = indexContent,
        Acl = "public-read",
        Key = "index.html", // Set the key of the object.
        ContentType = "text/html; charset=utf-8", // Set the MIME type of the file.
    }, new CustomResourceOptions
    {
        DependsOn =
        {
            publicAccessBlock,
            ownershipControls,
            website,
        },
    });

    // Export the website url.
    return new Dictionary<string, object?>
    {
        ["website_url"] = website.WebsiteEndpoint
    };
});

```

<!-- /option -->

<!-- option: java -->

**Note:** This tutorial is based on the `InlineProgram` example, which is a complete example of how to construct a simple Automation API program.

```java
private static void pulumiProgram(Context ctx) {

    // Create an AWS resource (S3 Bucket)
    var siteBucket = new Bucket("s3-website-bucket");

    var website = new BucketWebsiteConfigurationV2("website", BucketWebsiteConfigurationV2Args.builder()
            .bucket(siteBucket.id())
            .indexDocument(BucketWebsiteConfigurationV2IndexDocumentArgs.builder()
                    .suffix("index.html")
                    .build())
            .build());

    var ownershipControls = new BucketOwnershipControls("ownershipControls", BucketOwnershipControlsArgs.builder()
            .bucket(siteBucket.id())
            .rule(BucketOwnershipControlsRuleArgs.builder()
                    .objectOwnership("ObjectWriter")
                    .build())
            .build());

    var publicAccessBlock = new BucketPublicAccessBlock("publicAccessBlock", BucketPublicAccessBlockArgs.builder()
            .bucket(siteBucket.id())
            .blockPublicAcls(false)
            .build());

    String indexContent = """
            <html>
                <head><title>Hello S3</title><meta charset="UTF-8"></head>
                <body>
                    Hello, world!
                    Made with ❤️ with [Pulumi](https://pulumi.com)
                </body>
            </html>
            """;

    var indexHtml = new BucketObject("index.html", BucketObjectArgs.builder()
            .bucket(siteBucket.id())
            .content(indexContent)
            .contentType("text/html")
            .acl("public-read")
            .build(),
            CustomResourceOptions.builder()
                    .dependsOn(
                            publicAccessBlock,
                            ownershipControls,
                            website)
                    .build());

    // Export the name of the bucket
    ctx.export("website_url",
            website.websiteEndpoint().applyValue(websiteEndpoint -> String.format("http://%s", websiteEndpoint)));
}

```

<!-- /option -->

<!-- /chooser -->

> **Warning:** The program's lifecycle must be fully contained within the function, callback, or closure passed as the inline program. It's unsafe to perform actions outside the scope of the inline program function. Doing so can lead to unpredictable behavior.

## Associate with a stack

As with executing Pulumi programs through the CLI, you need to associate your Pulumi program with a `Stack`. Automation API provides methods to create or select stacks.

Here's a convenient method to select an existing `Stack` or create one if none exists:

<!-- chooser: language -->

<!-- option: typescript -->
```typescript
const args: InlineProgramArgs = {
    stackName: "dev",
    projectName: "inlineNode",
    program: pulumiProgram
};

const stack = await LocalWorkspace.createOrSelectStack(args);

```

<!-- /option -->

<!-- option: python -->
```python
project_name = "inline_s3_project"
stack_name = "dev"

stack = auto.create_or_select_stack(stack_name=stack_name,
                                    project_name=project_name,
                                    program=pulumi_program)

```

<!-- /option -->

<!-- option: go -->
```go
projectName := "inlineS3Project"
stackName := "dev"
s, err := auto.UpsertStackInlineSource(ctx, stackName, projectName, deployFunc)

```

<!-- /option -->

<!-- option: csharp -->
```csharp
var projectName = "inline_s3_project";
var stackName = "dev";

var stackArgs = new InlineProgramArgs(projectName, stackName, program);
var stack = await LocalWorkspace.CreateOrSelectStackAsync(stackArgs);

```

<!-- /option -->

<!-- option: java -->
```java
var projectName = "inline_s3_project_java";
var stackName = "dev";
var stack = LocalWorkspace.createOrSelectStack(projectName, stackName, App::pulumiProgram);

```

<!-- /option -->

<!-- /chooser -->

A `Stack` object operates within the context of a `Workspace`. A `Workspace` is the execution context containing a single Pulumi project, a program, and multiple stacks. Workspaces are used to manage the execution environment, providing various utilities such as plugin installation, environment configuration (`$PULUMI_HOME`), and creation, deletion, and listing of stacks. Because you are deploying AWS resources in this tutorial, you must install the AWS provider plugin within your `Workspace` so that your Pulumi program will have it available during execution.

## Configure your provider plugins

The AWS plugin also needs configuration. You can provide that configuration just as you would with other Pulumi programs: either through [stack configuration](/docs/concepts/config/) or environment variables. In this tutorial, you'll use the `Stack` object to set the AWS region for the AWS provider plugin.

<!-- chooser: language -->

<!-- option: typescript -->
```typescript
await stack.workspace.installPlugin("aws", "v4.0.0");
await stack.setConfig("aws:region", { value: "us-west-2" });

```

<!-- /option -->

<!-- option: python -->
```python
stack.workspace.install_plugin("aws", "v4.0.0")
stack.set_config("aws:region", auto.ConfigValue(value="us-west-2"))

```

<!-- /option -->

<!-- option: go -->
```go
err = w.InstallPlugin(ctx, "aws", "v4.0.0")
if err != nil {
  fmt.Printf("Failed to install program plugins: %v\n", err)
  os.Exit(1)
}

s.SetConfig(ctx, "aws:region", auto.ConfigValue{Value: "us-west-2"})

```

<!-- /option -->

<!-- option: csharp -->
```csharp
await stack.Workspace.InstallPluginAsync("aws", "v4.0.0");
await stack.SetConfigAsync("aws:region", new ConfigValue("us-west-2"));

```

<!-- /option -->

<!-- option: java -->
```java
stack.getWorkspace().installPlugin("aws", "v5.41.0");
stack.setConfig("aws:region", new ConfigValue("us-west-2"));

```

<!-- /option -->

<!-- /chooser -->

## Using local packages with Automation API {#using-local-packages-with-automation-api}

When working with Automation API, you may need to use [local packages](/docs/iac/guides/building-extending/packages/local-packages/) that aren't published to the Pulumi Registry. This is common when using parameterized providers like [`terraform-provider`](/registry/packages/terraform-provider/) or when developing custom providers.

### Generating and installing local packages

To use a local package with Automation API, you need to:

1. Generate the SDK for your target language using [`pulumi package add`](/docs/iac/cli/commands/pulumi_package_add/)
1. Manually install the plugin (not the provider) in your workspace
1. Reference the generated SDK in your Automation API program

> **Warning:** For local packages, you must install the **plugin**, not the provider. The plugin is what the Pulumi engine uses to communicate with resources during deployments.

### Example: Using a local Terraform provider

Here's how to use a locally-generated Terraform provider SDK with Automation API:

<!-- chooser: language -->

<!-- option: typescript -->
First, generate the SDK:
```bash
pulumi package add terraform-provider@1.0.2 hashicorp/random 3.5.1

```

Then, in your Automation API program, install the plugin in the workspace:
```typescript
import * as automation from "@pulumi/pulumi/automation";
import * as random from "@pulumi/random";

const stack = await automation.LocalWorkspace.createOrSelectStack({
    stackName: "dev",
    projectName: "myProject",
    program: async () => {
        const pet = new random.Pet("my-pet", { length: 2 });
        return { petName: pet.id };
    }
});

// Install the plugin for the local package
await stack.workspace.installPlugin("terraform-provider", "v1.0.2");

// Configure any required settings
await stack.setConfig("aws:region", { value: "us-west-2" });

// Run the deployment
const result = await stack.up({ onOutput: console.info });

```

<!-- /option -->

<!-- option: python -->
First, generate the SDK:
```bash
pulumi package add terraform-provider@1.0.2 hashicorp/random 3.5.1

```

Then, in your Automation API program, install the plugin in the workspace:
```python
import pulumi
import pulumi_random as random
from pulumi import automation as auto

def pulumi_program():
    pet = random.Pet("my-pet", length=2)
    pulumi.export("pet_name", pet.id)

# Create or select a stack
stack = auto.create_or_select_stack(
    stack_name="dev",
    project_name="myProject",
    program=pulumi_program
)

# Install the plugin for the local package
stack.workspace.install_plugin("terraform-provider", "v1.0.2")

# Configure any required settings
stack.set_config("aws:region", auto.ConfigValue(value="us-west-2"))

# Run the deployment
result = stack.up(on_output=print)

```

<!-- /option -->

<!-- option: go -->
First, generate the SDK:
```bash
pulumi package add terraform-provider@1.0.2 hashicorp/random 3.5.1

```

Then, in your Automation API program, install the plugin in the workspace:
```go
package main

import (
	"context"
	"fmt"
	"os"

	"github.com/pulumi/pulumi/sdk/v3/go/auto"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
	"github.com/pulumi/pulumi-random/sdk/v4/go/random"
)

func main() {
	ctx := context.Background()

	// Define the Pulumi program
	program := func(ctx *pulumi.Context) error {
		pet, err := random.NewPet(ctx, "my-pet", &random.PetArgs{
			Length: pulumi.Float64(2),
		})
		if err != nil {
			return err
		}
		ctx.Export("petName", pet.ID())
		return nil
	}

	// Create or select a stack
	s, err := auto.UpsertStackInlineSource(ctx, "dev", "myProject", program)
	if err != nil {
		fmt.Printf("Failed to create stack: %v\n", err)
		os.Exit(1)
	}

	// Install the plugin for the local package
	w := s.Workspace()
	err = w.InstallPlugin(ctx, "terraform-provider", "v1.0.2")
	if err != nil {
		fmt.Printf("Failed to install plugin: %v\n", err)
		os.Exit(1)
	}

	// Configure any required settings
	s.SetConfig(ctx, "aws:region", auto.ConfigValue{Value: "us-west-2"})

	// Run the deployment
	res, err := s.Up(ctx)
	if err != nil {
		fmt.Printf("Failed to update stack: %v\n", err)
		os.Exit(1)
	}

	fmt.Printf("Deployment succeeded! Pet name: %v\n", res.Outputs["petName"].Value)
}

```

<!-- /option -->

<!-- option: csharp -->
First, generate the SDK:
```bash
pulumi package add terraform-provider@1.0.2 hashicorp/random 3.5.1

```

Then, in your Automation API program, install the plugin in the workspace:
```csharp
using System;
using System.Collections.Generic;
using Pulumi.Automation;
using Pulumi.Random;

var program = PulumiFn.Create(() =>
{
    var pet = new RandomPet("my-pet", new RandomPetArgs { Length = 2 });
    return new Dictionary<string, object?>
    {
        ["petName"] = pet.Id
    };
});

var projectName = "myProject";
var stackName = "dev";

// Create or select a stack
var stackArgs = new InlineProgramArgs(projectName, stackName, program);
var stack = await LocalWorkspace.CreateOrSelectStackAsync(stackArgs);

// Install the plugin for the local package
await stack.Workspace.InstallPluginAsync("terraform-provider", "v1.0.2");

// Run the deployment
var result = await stack.UpAsync(new UpOptions { OnStandardOutput = Console.WriteLine });

```

<!-- /option -->

<!-- option: java -->
First, generate the SDK:
```bash
pulumi package add terraform-provider@1.0.2 hashicorp/random 3.5.1

```

Then, in your Automation API program, install the plugin in the workspace:
```java
import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.automation.*;
import com.pulumi.random.RandomPet;
import com.pulumi.random.RandomPetArgs;

public class App {
    public static void main(String[] args) {
        var projectName = "myProject";
        var stackName = "dev";

        // Define the Pulumi program
        var program = (Context ctx) -> {
            var pet = new RandomPet("my-pet", RandomPetArgs.builder()
                .length(2)
                .build());
            
            ctx.export("petName", pet.id());
        };
        
        try {
            // Create or select a stack
            var stack = LocalWorkspace.createOrSelectStack(LocalProgramArgs.builder()
                .stackName(stackName)
                .projectName(projectName)
                .program(program)
                .build());
            
            // Install the plugin for the local package
            stack.workspace().installPlugin("terraform-provider", "v1.0.2");
            
            // Run the deployment
            var result = stack.up(UpOptions.builder()
                .onOutput(System.out::println)
                .build());
            
            System.out.printf("Deployment succeeded! Pet name: %s%n", 
                result.outputs().get("petName").value());
        } catch (Exception e) {
            System.err.println("Error: " + e.getMessage());
            e.printStackTrace();
        }
    }
}

```

<!-- /option -->

<!-- /chooser -->

For more information about working with local packages, see the [Local Packages guide](/docs/iac/guides/building-extending/packages/local-packages/).

## Invoke Pulumi commands against the stack

You're now ready to execute commands against the `Stack`, including update, preview, refresh, destroy, import, and export.
If you want to update the stack, invoke the update method (`up`) against the `Stack` object:

<!-- chooser: language -->

<!-- option: typescript -->
```typescript
const upRes = await stack.up({ onOutput: console.info });

```

<!-- /option -->

<!-- option: python -->
```python
up_res = stack.up(on_output=print)

```

<!-- /option -->

<!-- option: go -->
```go
res, err := s.Up(ctx, stdoutStreamer)
if err != nil {
  fmt.Printf("Failed to update stack: %v\n\n", err)
  os.Exit(1)
}

```

<!-- /option -->

<!-- option: csharp -->
```csharp
var result = await stack.UpAsync(new UpOptions { OnStandardOutput = Console.WriteLine });

```

<!-- /option -->

<!-- option: java -->
```java
var result = stack.up(UpOptions.builder().onStandardOutput(System.out::println).build());

```

<!-- /option -->

<!-- /chooser -->

Notice how you can choose to have a callback function for standard output. In addition, the command returns a result of the update, which you can programmatically use to drive decisions within your program. For example, the result includes the stack outputs as well as a summary of the changes. This means you could choose to take different actions if there were no resources updated. Conversely, you could use the stack outputs to drive another Pulumi program within the same Automation program.

## Next steps

You've now seen how to define, configure, and deploy an inline program with Automation API. To go further:

- Review the [Automation API concepts](/docs/iac/concepts/automation-api/) to understand workspaces, stacks, and the difference between inline and local programs.
- Explore the [`automation-api-examples` repository](https://github.com/pulumi/automation-api-examples) for runnable examples in every supported language, covering patterns such as cross-language programs, database migrations, and exposing Pulumi over HTTP.

