| name | pulumi-go |
| description | Creates Pulumi infrastructure-as-code projects in Go, configures OIDC authentication, integrates with Pulumi ESC for centralized secrets and configuration management, and builds multi-language component resources. Use when setting up Pulumi Go projects, writing infrastructure code with Go, configuring OIDC for Pulumi, using Pulumi ESC with Go, automating cloud infrastructure with Golang, creating reusable Pulumi components in Go, or working with pulumi-go-provider. Also use when the user mentions Pulumi with Go/Golang, AWS/Azure/GCP infrastructure in Go, or Go-based ComponentResource patterns. |
Pulumi Go Skill
Development Workflow
1. Project Setup
pulumi new go
pulumi new aws-go
pulumi new azure-go
pulumi new gcp-go
2. Pulumi ESC Integration
Link ESC environment to stack:
pulumi env init myorg/myproject-dev
pulumi env edit myorg/myproject-dev
pulumi config env add myorg/myproject-dev
ESC environment definition (YAML):
values:
pulumiConfig:
aws:region: us-west-2
myapp:instanceType: t3.medium
aws:
login:
fn::open::aws-login:
oidc:
roleArn: arn:aws:iam::123456789:role/pulumi-oidc
sessionName: pulumi-deploy
secrets:
fn::open::aws-secrets:
region: us-west-2
login: ${aws.login}
get:
dbPassword:
secretId: prod/database/password
environmentVariables:
AWS_ACCESS_KEY_ID: ${aws.login.accessKeyId}
AWS_SECRET_ACCESS_KEY: ${aws.login.secretAccessKey}
AWS_SESSION_TOKEN: ${aws.login.sessionToken}
3. Go Patterns
Basic resource creation:
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v6/go/aws/s3"
"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 {
cfg := config.New(ctx, "")
instanceType := cfg.Require("instanceType")
bucket, err := s3.NewBucket(ctx, "my-bucket", &s3.BucketArgs{
Versioning: &s3.BucketVersioningArgs{
Enabled: pulumi.Bool(true),
},
ServerSideEncryptionConfiguration: &s3.BucketServerSideEncryptionConfigurationArgs{
Rule: &s3.BucketServerSideEncryptionConfigurationRuleArgs{
ApplyServerSideEncryptionByDefault: &s3.BucketServerSideEncryptionConfigurationRuleApplyServerSideEncryptionByDefaultArgs{
SseAlgorithm: pulumi.String("AES256"),
},
},
},
Tags: pulumi.StringMap{
"Environment": pulumi.String(ctx.Stack()),
"ManagedBy": pulumi.String("Pulumi"),
},
})
if err != nil {
return err
}
ctx.Export("bucketName", bucket.ID())
ctx.Export("bucketArn", bucket.Arn)
return nil
})
}
Component resources:
package main
import (
"github.com/pulumi/pulumi-aws/sdk/v6/go/aws/lb"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
type WebServiceArgs struct {
Port pulumi.IntInput
ImageUri pulumi.StringInput
}
type WebService struct {
pulumi.ResourceState
URL pulumi.StringOutput `pulumi:"url"`
}
func NewWebService(ctx *pulumi.Context, name string, args *WebServiceArgs, opts ...pulumi.ResourceOption) (*WebService, error) {
component := &WebService{}
err := ctx.RegisterComponentResource("custom:app:WebService", name, component, opts...)
if err != nil {
return nil, err
}
loadBalancer, err := lb.NewLoadBalancer(ctx, name+"-lb", &lb.LoadBalancerArgs{
LoadBalancerType: pulumi.String("application"),
}, pulumi.Parent(component))
if err != nil {
return nil, err
}
component.URL = loadBalancer.DnsName
ctx.RegisterResourceOutputs(component, pulumi.Map{
"url": component.URL,
})
return component, nil
}
Stack references for cross-stack dependencies:
package main
import (
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
networkingStack, err := pulumi.NewStackReference(ctx, "myorg/networking/prod", nil)
if err != nil {
return err
}
vpcId := networkingStack.GetStringOutput(pulumi.String("vpcId"))
subnetIds := networkingStack.GetOutput(pulumi.String("privateSubnetIds"))
ctx.Export("vpcId", vpcId)
return nil
})
}
Working with Outputs:
package main
import (
"fmt"
"strings"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
uppercaseName := bucket.ID().ApplyT(func(id string) string {
return strings.ToUpper(id)
}).(pulumi.StringOutput)
combined := pulumi.All(bucket.ID(), bucket.Arn).ApplyT(
func(args []interface{}) string {
id := args[0].(string)
arn := args[1].(string)
return fmt.Sprintf("Bucket %s has ARN %s", id, arn)
},
).(pulumi.StringOutput)
if ctx.Stack() == "prod" {
_, err := cloudwatch.NewMetricAlarm(ctx, "alarm", &cloudwatch.MetricAlarmArgs{
})
if err != nil {
return err
}
}
return nil
})
}
4. Using ESC with pulumi env run
pulumi env run myorg/aws-dev -- pulumi up
pulumi env run myorg/test-env -- go test ./...
pulumi env open myorg/myproject-dev --format shell
5. Deployment Workflow with Validation
Build and preview:
go build -o $(basename $(pwd))
pulumi preview
Validation checkpoint: Review the preview output. If changes are unexpected:
- Check ESC environment values:
pulumi env open myorg/myproject-dev
- Verify stack config:
pulumi config
- Inspect resource diffs carefully before proceeding
Deploy:
pulumi up
pulumi stack output
Error recovery: If deployment fails:
- Check error logs for resource-specific issues
- Verify credentials and permissions:
pulumi env open myorg/myproject-dev --format shell
- Attempt rollback if needed:
pulumi refresh (updates state without changes)
- Fix the issue and retry:
pulumi up
For destructive changes (deletions), Pulumi will prompt for confirmation during pulumi up.
6. Error Handling
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
bucket, err := s3.NewBucket(ctx, "bucket", &s3.BucketArgs{})
if err != nil {
return fmt.Errorf("failed to create bucket: %w", err)
}
policy, err := s3.NewBucketPolicy(ctx, "policy", &s3.BucketPolicyArgs{
Bucket: bucket.ID(),
Policy: bucket.Arn.ApplyT(func(arn string) string {
return fmt.Sprintf(`{"Version":"2012-10-17",...}`, arn)
}).(pulumi.StringOutput),
})
if err != nil {
return fmt.Errorf("failed to create bucket policy: %w", err)
}
return nil
})
}
7. Multi-Language Components
Create reusable components in Go for consumption from any Pulumi language.
Project structure:
my-component/
├── PulumiPlugin.yaml
├── go.mod
├── go.sum
└── main.go
PulumiPlugin.yaml:
runtime: go
Component implementation:
package main
import (
"context"
"log"
"github.com/pulumi/pulumi-aws/sdk/v6/go/aws/s3"
"github.com/pulumi/pulumi-go-provider/infer"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
type SecureBucketArgs struct {
BucketName pulumi.StringInput `pulumi:"bucketName"`
EnableVersioning pulumi.BoolInput `pulumi:"enableVersioning,optional"`
Tags pulumi.StringMapInput `pulumi:"tags,optional"`
}
type SecureBucket struct {
pulumi.ResourceState
BucketId pulumi.StringOutput `pulumi:"bucketId"`
BucketArn pulumi.StringOutput `pulumi:"bucketArn"`
}
func NewSecureBucket(ctx *pulumi.Context, name string, args *SecureBucketArgs, opts ...pulumi.ResourceOption) (*SecureBucket, error) {
component := &SecureBucket{}
err := ctx.RegisterComponentResource("myorg:storage:SecureBucket", name, component, opts...)
if err != nil {
return nil, err
}
bucket, err := s3.NewBucket(ctx, name+"-bucket", &s3.BucketArgs{
Bucket: args.BucketName,
Versioning: &s3.BucketVersioningArgs{
Enabled: args.EnableVersioning,
},
ServerSideEncryptionConfiguration: &s3.BucketServerSideEncryptionConfigurationArgs{
Rule: &s3.BucketServerSideEncryptionConfigurationRuleArgs{
ApplyServerSideEncryptionByDefault: &s3.BucketServerSideEncryptionConfigurationRuleApplyServerSideEncryptionByDefaultArgs{
SseAlgorithm: pulumi.String("AES256"),
},
},
},
Tags: args.Tags,
}, pulumi.Parent(component))
if err != nil {
return nil, err
}
component.BucketId = bucket.ID().ToStringOutput()
component.BucketArn = bucket.Arn
ctx.RegisterResourceOutputs(component, pulumi.Map{
"bucketId": component.BucketId,
"bucketArn": component.BucketArn,
})
return component, nil
}
func main() {
prov, err := infer.NewProviderBuilder().
WithNamespace("myorg").
WithComponents(
infer.ComponentF(NewSecureBucket),
).
Build()
if err != nil {
log.Fatal(err.Error())
}
_ = prov.Run(context.Background(), "go-components", "v0.0.1")
}
Publishing:
pulumi package add github.com/myorg/my-component
pulumi package add github.com/myorg/my-component@v1.0.0
pulumi package add /path/to/local/my-component
Best Practices
Security
- Use Pulumi ESC for all secrets — never commit secrets to stack config files
- Enable OIDC authentication instead of static credentials
- Use dynamic secrets with short TTLs when possible
- Apply least-privilege IAM policies
Code Organization
- Use Component Resources for reusable infrastructure patterns
- Leverage Go's type system for configuration validation
- Keep stack-specific config in ESC environments
- Use stack references for cross-stack dependencies
Deployment
- Always run
pulumi preview before pulumi up and review changes carefully
- Use ESC environment versioning and tags for releases
- Implement proper tagging strategy for all resources
- Build your Go program before running Pulumi:
go build -o $(basename $(pwd))
Common Commands
pulumi env init <org>/<project>/<env>
pulumi env edit <org>/<env>
pulumi env open <org>/<env>
pulumi env run <org>/<env> -- <command>
pulumi env version tag <org>/<env> <tag>
pulumi new go
pulumi config env add <org>/<env>
go build -o $(basename $(pwd))
pulumi preview
pulumi up
pulumi stack output
pulumi destroy
References