Invoke AWS Lambda Functions

The aws:lambda/invocation:Invocation resource, part of the Pulumi AWS provider, invokes a Lambda function synchronously during Pulumi operations and captures its response. This guide focuses on three capabilities: one-time invocation during stack creation, trigger-based re-invocation on configuration changes, and lifecycle event handling across create, update, and delete operations.

Invocations reference existing Lambda functions and assume those functions have appropriate IAM permissions for their operations. The examples are intentionally small. Combine them with your own Lambda functions and error handling logic.

Invoke a function once during stack creation

Many workflows need initialization logic when infrastructure is first deployed, such as seeding databases or configuring services.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as std from "@pulumi/std";

// Lambda function to invoke
const example = new aws.lambda.Function("example", {
    code: new pulumi.asset.FileArchive("function.zip"),
    name: "data_processor",
    role: lambdaRole.arn,
    handler: "index.handler",
    runtime: aws.lambda.Runtime.Python3d12,
});
// Invoke the function once during resource creation
const exampleInvocation = new aws.lambda.Invocation("example", {
    functionName: example.name,
    input: JSON.stringify({
        operation: "initialize",
        config: {
            environment: "production",
            debug: false,
        },
    }),
});
export const initializationResult = std.jsondecodeOutput({
    input: exampleInvocation.result,
}).apply(invoke => invoke.result?.status);
import pulumi
import json
import pulumi_aws as aws
import pulumi_std as std

# Lambda function to invoke
example = aws.lambda_.Function("example",
    code=pulumi.FileArchive("function.zip"),
    name="data_processor",
    role=lambda_role["arn"],
    handler="index.handler",
    runtime=aws.lambda_.Runtime.PYTHON3D12)
# Invoke the function once during resource creation
example_invocation = aws.lambda_.Invocation("example",
    function_name=example.name,
    input=json.dumps({
        "operation": "initialize",
        "config": {
            "environment": "production",
            "debug": False,
        },
    }))
pulumi.export("initializationResult", std.jsondecode_output(input=example_invocation.result).apply(lambda invoke: invoke.result["status"]))
package main

import (
	"encoding/json"

	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/lambda"
	"github.com/pulumi/pulumi-std/sdk/go/std"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
// Lambda function to invoke
example, err := lambda.NewFunction(ctx, "example", &lambda.FunctionArgs{
Code: pulumi.NewFileArchive("function.zip"),
Name: pulumi.String("data_processor"),
Role: pulumi.Any(lambdaRole.Arn),
Handler: pulumi.String("index.handler"),
Runtime: pulumi.String(lambda.RuntimePython3d12),
})
if err != nil {
return err
}
tmpJSON0, err := json.Marshal(map[string]interface{}{
"operation": "initialize",
"config": map[string]interface{}{
"environment": "production",
"debug": false,
},
})
if err != nil {
return err
}
json0 := string(tmpJSON0)
// Invoke the function once during resource creation
exampleInvocation, err := lambda.NewInvocation(ctx, "example", &lambda.InvocationArgs{
FunctionName: example.Name,
Input: pulumi.String(json0),
})
if err != nil {
return err
}
ctx.Export("initializationResult", std.JsondecodeOutput(ctx, std.JsondecodeOutputArgs{
Input: exampleInvocation.Result,
}, nil).ApplyT(func(invoke std.JsondecodeResult) (*interface{}, error) {
return invoke.Result.Status, nil
}).(pulumi.Interface{}PtrOutput))
return nil
})
}
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Pulumi;
using Aws = Pulumi.Aws;
using Std = Pulumi.Std;

return await Deployment.RunAsync(() => 
{
    // Lambda function to invoke
    var example = new Aws.Lambda.Function("example", new()
    {
        Code = new FileArchive("function.zip"),
        Name = "data_processor",
        Role = lambdaRole.Arn,
        Handler = "index.handler",
        Runtime = Aws.Lambda.Runtime.Python3d12,
    });

    // Invoke the function once during resource creation
    var exampleInvocation = new Aws.Lambda.Invocation("example", new()
    {
        FunctionName = example.Name,
        Input = JsonSerializer.Serialize(new Dictionary<string, object?>
        {
            ["operation"] = "initialize",
            ["config"] = new Dictionary<string, object?>
            {
                ["environment"] = "production",
                ["debug"] = false,
            },
        }),
    });

    return new Dictionary<string, object?>
    {
        ["initializationResult"] = Std.Jsondecode.Invoke(new()
        {
            Input = exampleInvocation.Result,
        }).Apply(invoke => invoke.Result?.Status),
    };
});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.lambda.Function;
import com.pulumi.aws.lambda.FunctionArgs;
import com.pulumi.aws.lambda.Invocation;
import com.pulumi.aws.lambda.InvocationArgs;
import com.pulumi.std.StdFunctions;
import com.pulumi.std.inputs.JsondecodeArgs;
import com.pulumi.asset.FileArchive;
import static com.pulumi.codegen.internal.Serialization.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        // Lambda function to invoke
        var example = new Function("example", FunctionArgs.builder()
            .code(new FileArchive("function.zip"))
            .name("data_processor")
            .role(lambdaRole.arn())
            .handler("index.handler")
            .runtime("python3.12")
            .build());

        // Invoke the function once during resource creation
        var exampleInvocation = new Invocation("exampleInvocation", InvocationArgs.builder()
            .functionName(example.name())
            .input(serializeJson(
                jsonObject(
                    jsonProperty("operation", "initialize"),
                    jsonProperty("config", jsonObject(
                        jsonProperty("environment", "production"),
                        jsonProperty("debug", false)
                    ))
                )))
            .build());

        ctx.export("initializationResult", StdFunctions.jsondecode(JsondecodeArgs.builder()
            .input(exampleInvocation.result())
            .build()).applyValue(_invoke -> _invoke.result().status()));
    }
}
resources:
  # Lambda function to invoke
  example:
    type: aws:lambda:Function
    properties:
      code:
        fn::FileArchive: function.zip
      name: data_processor
      role: ${lambdaRole.arn}
      handler: index.handler
      runtime: python3.12
  # Invoke the function once during resource creation
  exampleInvocation:
    type: aws:lambda:Invocation
    name: example
    properties:
      functionName: ${example.name}
      input:
        fn::toJSON:
          operation: initialize
          config:
            environment: production
            debug: false
outputs:
  # Use the result in other resources
  initializationResult:
    fn::invoke:
      function: std:jsondecode
      arguments:
        input: ${exampleInvocation.result}
      return: result.status

When the stack is created, Pulumi invokes the Lambda function with the provided JSON payload and waits for the response. The result property captures the function’s return value, which you can parse and export. By default, the function is only invoked once; subsequent applies don’t re-invoke unless the input changes or the resource is replaced.

Re-invoke when configuration or dependencies change

Some Lambda functions need to run whenever their configuration changes or when upstream resources are updated.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as std from "@pulumi/std";

const example = new aws.lambda.Invocation("example", {
    functionName: exampleAwsLambdaFunction.functionName,
    triggers: {
        function_version: exampleAwsLambdaFunction.version,
        config_hash: std.sha256Output({
            input: JSON.stringify({
                environment: environment,
                timestamp: std.timestamp({}).then(invoke => invoke.result),
            }),
        }).apply(invoke => invoke.result),
    },
    input: JSON.stringify({
        operation: "process_data",
        environment: environment,
        batch_id: batchId.result,
    }),
});
import pulumi
import json
import pulumi_aws as aws
import pulumi_std as std

example = aws.lambda_.Invocation("example",
    function_name=example_aws_lambda_function["functionName"],
    triggers={
        "function_version": example_aws_lambda_function["version"],
        "config_hash": std.sha256_output(input=json.dumps({
            "environment": environment,
            "timestamp": std.timestamp().result,
        })).apply(lambda invoke: invoke.result),
    },
    input=json.dumps({
        "operation": "process_data",
        "environment": environment,
        "batch_id": batch_id["result"],
    }))
package main

import (
	"encoding/json"

	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/lambda"
	"github.com/pulumi/pulumi-std/sdk/go/std"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		tmpJSON0, err := json.Marshal(map[string]interface{}{
			"environment": environment,
			"timestamp":   std.Timestamp(ctx, &std.TimestampArgs{}, nil).Result,
		})
		if err != nil {
			return err
		}
		json0 := string(tmpJSON0)
		tmpJSON1, err := json.Marshal(map[string]interface{}{
			"operation":   "process_data",
			"environment": environment,
			"batch_id":    batchId.Result,
		})
		if err != nil {
			return err
		}
		json1 := string(tmpJSON1)
		_, err = lambda.NewInvocation(ctx, "example", &lambda.InvocationArgs{
			FunctionName: pulumi.Any(exampleAwsLambdaFunction.FunctionName),
			Triggers: pulumi.StringMap{
				"function_version": pulumi.Any(exampleAwsLambdaFunction.Version),
				"config_hash": pulumi.String(std.Sha256Output(ctx, std.Sha256OutputArgs{
					Input: pulumi.String(json0),
				}, nil).ApplyT(func(invoke std.Sha256Result) (*string, error) {
					return invoke.Result, nil
				}).(pulumi.StringPtrOutput)),
			},
			Input: pulumi.String(json1),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Pulumi;
using Aws = Pulumi.Aws;
using Std = Pulumi.Std;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.Lambda.Invocation("example", new()
    {
        FunctionName = exampleAwsLambdaFunction.FunctionName,
        Triggers = 
        {
            { "function_version", exampleAwsLambdaFunction.Version },
            { "config_hash", Std.Sha256.Invoke(new()
            {
                Input = JsonSerializer.Serialize(new Dictionary<string, object?>
                {
                    ["environment"] = environment,
                    ["timestamp"] = Std.Timestamp.Invoke().Apply(invoke => invoke.Result),
                }),
            }).Apply(invoke => invoke.Result) },
        },
        Input = JsonSerializer.Serialize(new Dictionary<string, object?>
        {
            ["operation"] = "process_data",
            ["environment"] = environment,
            ["batch_id"] = batchId.Result,
        }),
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.lambda.Invocation;
import com.pulumi.aws.lambda.InvocationArgs;
import com.pulumi.std.StdFunctions;
import com.pulumi.std.inputs.TimestampArgs;
import com.pulumi.std.inputs.Sha256Args;
import static com.pulumi.codegen.internal.Serialization.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new Invocation("example", InvocationArgs.builder()
            .functionName(exampleAwsLambdaFunction.functionName())
            .triggers(Map.ofEntries(
                Map.entry("function_version", exampleAwsLambdaFunction.version()),
                Map.entry("config_hash", StdFunctions.sha256(Sha256Args.builder()
                    .input(serializeJson(
                        jsonObject(
                            jsonProperty("environment", environment),
                            jsonProperty("timestamp", StdFunctions.timestamp(TimestampArgs.builder()
                                .build()).result())
                        )))
                    .build()).applyValue(_invoke -> _invoke.result()))
            ))
            .input(serializeJson(
                jsonObject(
                    jsonProperty("operation", "process_data"),
                    jsonProperty("environment", environment),
                    jsonProperty("batch_id", batchId.result())
                )))
            .build());

    }
}
resources:
  example:
    type: aws:lambda:Invocation
    properties:
      functionName: ${exampleAwsLambdaFunction.functionName}
      triggers:
        function_version: ${exampleAwsLambdaFunction.version}
        config_hash:
          fn::invoke:
            function: std:sha256
            arguments:
              input:
                fn::toJSON:
                  environment: ${environment}
                  timestamp:
                    fn::invoke:
                      function: std:timestamp
                      arguments: {}
                      return: result
            return: result
      input:
        fn::toJSON:
          operation: process_data
          environment: ${environment}
          batch_id: ${batchId.result}

The triggers property accepts a map of arbitrary keys and values. When any value in the map changes, Pulumi re-invokes the function. Here, the function runs again when the Lambda version changes or when the configuration hash changes. This is useful for processing tasks that depend on external state.

Handle create, update, and delete lifecycle events

Infrastructure provisioning often requires coordination across lifecycle events. A database migration might need setup on create, schema updates on change, and cleanup on delete.

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";

const example = new aws.lambda.Invocation("example", {
    functionName: exampleAwsLambdaFunction.functionName,
    input: JSON.stringify({
        resource_name: "database_setup",
        database_url: exampleAwsDbInstance.endpoint,
        credentials: {
            username: dbUsername,
            password: dbPassword,
        },
    }),
    lifecycleScope: "CRUD",
});
import pulumi
import json
import pulumi_aws as aws

example = aws.lambda_.Invocation("example",
    function_name=example_aws_lambda_function["functionName"],
    input=json.dumps({
        "resource_name": "database_setup",
        "database_url": example_aws_db_instance["endpoint"],
        "credentials": {
            "username": db_username,
            "password": db_password,
        },
    }),
    lifecycle_scope="CRUD")
package main

import (
	"encoding/json"

	"github.com/pulumi/pulumi-aws/sdk/v7/go/aws/lambda"
	"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)

func main() {
	pulumi.Run(func(ctx *pulumi.Context) error {
		tmpJSON0, err := json.Marshal(map[string]interface{}{
			"resource_name": "database_setup",
			"database_url":  exampleAwsDbInstance.Endpoint,
			"credentials": map[string]interface{}{
				"username": dbUsername,
				"password": dbPassword,
			},
		})
		if err != nil {
			return err
		}
		json0 := string(tmpJSON0)
		_, err = lambda.NewInvocation(ctx, "example", &lambda.InvocationArgs{
			FunctionName:   pulumi.Any(exampleAwsLambdaFunction.FunctionName),
			Input:          pulumi.String(json0),
			LifecycleScope: pulumi.String("CRUD"),
		})
		if err != nil {
			return err
		}
		return nil
	})
}
using System.Collections.Generic;
using System.Linq;
using System.Text.Json;
using Pulumi;
using Aws = Pulumi.Aws;

return await Deployment.RunAsync(() => 
{
    var example = new Aws.Lambda.Invocation("example", new()
    {
        FunctionName = exampleAwsLambdaFunction.FunctionName,
        Input = JsonSerializer.Serialize(new Dictionary<string, object?>
        {
            ["resource_name"] = "database_setup",
            ["database_url"] = exampleAwsDbInstance.Endpoint,
            ["credentials"] = new Dictionary<string, object?>
            {
                ["username"] = dbUsername,
                ["password"] = dbPassword,
            },
        }),
        LifecycleScope = "CRUD",
    });

});
package generated_program;

import com.pulumi.Context;
import com.pulumi.Pulumi;
import com.pulumi.core.Output;
import com.pulumi.aws.lambda.Invocation;
import com.pulumi.aws.lambda.InvocationArgs;
import static com.pulumi.codegen.internal.Serialization.*;
import java.util.List;
import java.util.ArrayList;
import java.util.Map;
import java.io.File;
import java.nio.file.Files;
import java.nio.file.Paths;

public class App {
    public static void main(String[] args) {
        Pulumi.run(App::stack);
    }

    public static void stack(Context ctx) {
        var example = new Invocation("example", InvocationArgs.builder()
            .functionName(exampleAwsLambdaFunction.functionName())
            .input(serializeJson(
                jsonObject(
                    jsonProperty("resource_name", "database_setup"),
                    jsonProperty("database_url", exampleAwsDbInstance.endpoint()),
                    jsonProperty("credentials", jsonObject(
                        jsonProperty("username", dbUsername),
                        jsonProperty("password", dbPassword)
                    ))
                )))
            .lifecycleScope("CRUD")
            .build());

    }
}
resources:
  example:
    type: aws:lambda:Invocation
    properties:
      functionName: ${exampleAwsLambdaFunction.functionName}
      input:
        fn::toJSON:
          resource_name: database_setup
          database_url: ${exampleAwsDbInstance.endpoint}
          credentials:
            username: ${dbUsername}
            password: ${dbPassword}
      lifecycleScope: CRUD

Setting lifecycleScope to “CRUD” invokes the function during create, update, and delete operations. Pulumi injects a “tf” key into your input JSON with two subkeys: action (create, update, or delete) and prev_input (the previous invocation’s payload). Your Lambda function can inspect these values to handle each lifecycle transition differently. When the resource is deleted, the function receives the final state with action set to “delete”.

Beyond these examples

These snippets focus on specific invocation features: one-time and trigger-based invocation, lifecycle event handling, and JSON payload construction and result capture. They’re intentionally minimal rather than full orchestration workflows.

The examples reference pre-existing infrastructure such as Lambda functions with appropriate execution roles, and IAM permissions for Lambda to perform operations in input payloads. They focus on invoking the function rather than provisioning the function itself.

To keep things focused, common invocation patterns are omitted, including:

  • Function versioning and aliases (qualifier)
  • Custom lifecycle key names (terraformKey)
  • Multi-tenant invocations (tenantId)
  • Error handling and retry logic

These omissions are intentional: the goal is to illustrate how each invocation feature is wired, not provide drop-in orchestration modules. See the Lambda Invocation resource reference for all available configuration options.

Let's invoke AWS Lambda Functions

Get started with Pulumi Cloud, then follow our quick setup guide to deploy this infrastructure.

Try Pulumi Cloud for FREE

Frequently Asked Questions

Invocation Behavior & Triggers
Why doesn't my Lambda function get invoked on every apply?
By default, the function only invokes during resource creation or replacement. If your input and other arguments don’t change, subsequent applies won’t trigger invocation. Use triggers to force re-invocation based on specific values, or set lifecycleScope to CRUD for lifecycle-based invocations.
How do I trigger re-invocation when my configuration changes?
Use the triggers property with a map of values that should trigger re-invocation when changed. For example, set function_version or a hash of your configuration. When any trigger value changes, the function will be invoked again.
CRUD Lifecycle Management
What's the difference between CREATE_ONLY and CRUD modes?
CREATE_ONLY (default) invokes the function only on creation or replacement. CRUD invokes on create, update, and delete, automatically injecting lifecycle metadata into your input JSON with an action field (create/update/delete) and prev_input field containing the previous payload.
What if I need to use a 'tf' key in my own input JSON?
When using lifecycleScope: CRUD, a tf key is automatically injected into your input payload. If this conflicts with your own data, override the key name using the pulumiKey argument.
Common Errors & Troubleshooting
Why am I getting KMSAccessDeniedException when invoking my function?
This occurs when the function’s IAM role was deleted and recreated after the function was created, invalidating the KMS grant. Fix it by updating the function’s role to a different role, then back to the recreated role, which causes Lambda to update the grant.
Import & State Management
What happens after I import an invocation resource?
Because previous invocation state cannot be retrieved, the next update after import will invoke the function again regardless of whether arguments have changed.

Using a different cloud?

Explore serverless guides for other cloud providers: