# How to Configure a Terraform Lambda Trigger for Scheduled Events

> Learn how to configure a Terraform Lambda trigger for scheduled events. Set up CloudWatch Event rules, targets, and permissions for automated Lambda execution.

- Repository: [HashiCorp/terraform](https://github.com/hashicorp/terraform)
- Tags: how-to-guide
- Published: 2026-02-19

---

**You can configure a terraform lambda trigger for scheduled events by creating an `aws_cloudwatch_event_rule` with a schedule expression, an `aws_cloudwatch_event_target` to link the rule to your Lambda, and an `aws_lambda_permission` to authorize CloudWatch Events to invoke the function.**

This guide demonstrates how to implement a terraform lambda trigger for AWS Lambda functions using scheduled event sources. Based on the architecture of the `hashicorp/terraform` repository, we'll explore how Terraform's core graph engine resolves dependencies between CloudWatch Events and Lambda resources to create reliable, time-based automation.

## Understanding the Terraform Lambda Trigger Architecture

A terraform lambda trigger for scheduled events requires wiring together four distinct AWS resources. When Terraform applies your configuration, it executes a dependency graph built by the core engine (see [`internal/terraform/transform_resource_count.go`](https://github.com/hashicorp/terraform/blob/main/internal/terraform/transform_resource_count.go) for the graph resolution logic) to ensure resources create in the correct order.

The four resources you need are:

- **`aws_lambda_function`** – The compute resource that executes your code.
- **`aws_cloudwatch_event_rule`** – Defines the schedule using either a `rate()` expression or a `cron()` expression.
- **`aws_lambda_permission`** – Grants CloudWatch Events service principal permission to invoke your specific Lambda function.
- **`aws_cloudwatch_event_target`** – Connects the rule to the Lambda by specifying the function ARN as the target.

## Complete Terraform Lambda Trigger Example

Below is a production-ready configuration that creates a Lambda function triggered every five minutes. This example demonstrates the complete resource chain required for a functional terraform lambda trigger.

```hcl

# -------------------------------------------------

# 1. The Lambda function (source code zipped in S3)

# -------------------------------------------------

resource "aws_lambda_function" "my_lambda" {
  function_name = "my-scheduled-function"
  role          = aws_iam_role.lambda_exec.arn
  handler       = "index.handler"
  runtime       = "nodejs20.x"

  # The .zip file containing the Lambda code

  s3_bucket = aws_s3_bucket.lambda_code.bucket
  s3_key    = aws_s3_bucket_object.lambda_zip.key
}

# -------------------------------------------------

# 2. IAM role for the Lambda (basic execution role)

# -------------------------------------------------

resource "aws_iam_role" "lambda_exec" {
  name = "lambda-exec-role"

  assume_role_policy = jsonencode({
    Version = "2012-10-17"
    Statement = [{
      Action    = "sts:AssumeRole"
      Effect    = "Allow"
      Principal = { Service = "lambda.amazonaws.com" }
    }]
  })
}

resource "aws_iam_role_policy_attachment" "lambda_basic" {
  role       = aws_iam_role.lambda_exec.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}

# -------------------------------------------------

# 3. CloudWatch Event rule (schedule)

# -------------------------------------------------

resource "aws_cloudwatch_event_rule" "every_five_minutes" {
  name                = "every-five-minutes"
  schedule_expression = "rate(5 minutes)"  # or use cron: "cron(0/5 * * * ? *)"

}

# -------------------------------------------------

# 4. Permission so CloudWatch can invoke the Lambda

# -------------------------------------------------

resource "aws_lambda_permission" "allow_cloudwatch" {
  statement_id  = "AllowExecutionFromCloudWatch"
  action        = "lambda:InvokeFunction"
  function_name = aws_lambda_function.my_lambda.function_name
  principal     = "events.amazonaws.com"
  source_arn    = aws_cloudwatch_event_rule.every_five_minutes.arn
}

# -------------------------------------------------

# 5. Attach the rule to the Lambda

# -------------------------------------------------

resource "aws_cloudwatch_event_target" "lambda_target" {
  rule      = aws_cloudwatch_event_rule.every_five_minutes.name
  target_id = "lambda"
  arn       = aws_lambda_function.my_lambda.arn
}

```

## Breaking Down the Resource Dependencies

Terraform's core engine resolves the implicit dependencies between these resources using graph transformations defined in `internal/terraform/transform_*.go` files. Understanding these relationships helps troubleshoot deployment failures.

### The Lambda Function Resource

The `aws_lambda_function` resource serves as the compute target. According to the provider loading mechanism in [`internal/getproviders/reattach/reattach.go`](https://github.com/hashicorp/terraform/blob/main/internal/getproviders/reattach/reattach.go), Terraform loads the AWS provider plugin which supplies this resource schema. The function must exist before you can attach triggers to it.

### The CloudWatch Event Rule

The `aws_cloudwatch_event_rule` defines the schedule expression. You can use either `rate()` for simple intervals or `cron()` for complex schedules. This resource creates the event bus rule but does not yet specify what runs when the rule fires.

### The Lambda Permission Resource

The `aws_lambda_permission` is critical for security. Without this resource, CloudWatch Events lacks the IAM authorization to invoke your function. The `source_arn` parameter ensures that only the specific CloudWatch rule can trigger the Lambda, following the principle of least privilege.

### The Event Target Resource

The `aws_cloudwatch_event_target` completes the circuit by declaring that the Lambda function (specified by `arn`) is the destination for the CloudWatch rule. Terraform's graph builder ensures this resource creates after both the Lambda and the rule exist, as documented in [`internal/terraform/transform_resource_count.go`](https://github.com/hashicorp/terraform/blob/main/internal/terraform/transform_resource_count.go).

## Key Files in the Terraform Core Repository

Understanding how Terraform processes your lambda trigger configuration requires familiarity with these core components:

| File | Role in Lambda Trigger Deployment |
|------|-----------------------------------|
| [`main.go`](https://github.com/hashicorp/terraform/blob/main/main.go) | Entry point that bootstraps the CLI, loads providers, and executes the plan/apply lifecycle for your terraform lambda trigger resources. |
| `internal/command/*` | Handles sub-commands such as `apply`, `plan`, and `destroy` that process your AWS resource definitions. |
| `internal/terraform/transform_*.go` | Implements the graph building logic that resolves inter-resource dependencies, ensuring the `aws_lambda_permission` creates after the Lambda function exists. |
| [`internal/getproviders/reattach/reattach.go`](https://github.com/hashicorp/terraform/blob/main/internal/getproviders/reattach/reattach.go) | Loads the AWS provider plugin that supplies the `aws_lambda_function` and `aws_cloudwatch_event_rule` resource schemas. |
| [`internal/terraform/upgrade_resource_state.go`](https://github.com/hashicorp/terraform/blob/main/internal/terraform/upgrade_resource_state.go) | Manages state upgrades when provider versions change, ensuring your terraform lambda trigger configuration remains compatible across Terraform updates. |

## Summary

Configuring a terraform lambda trigger for scheduled events requires orchestrating four AWS resources through explicit and implicit dependencies:

- Create the **`aws_lambda_function`** as your compute target.
- Define the schedule using **`aws_cloudwatch_event_rule`** with `rate()` or `cron()` expressions.
- Grant invocation rights via **`aws_lambda_permission`** to secure the trigger.
- Link the rule to the function using **`aws_cloudwatch_event_target`**.

Terraform's core graph engine, implemented in `internal/terraform/transform_*.go`, automatically resolves the creation order of these resources, ensuring your scheduled trigger deploys reliably.

## Frequently Asked Questions

### What is the difference between rate and cron expressions in a terraform lambda trigger?

**Rate expressions** use the format `rate(value unit)` (e.g., `rate(5 minutes)`) to trigger at regular intervals, while **cron expressions** use the format `cron(fields)` (e.g., `cron(0 12 * * ? *)`) for complex schedules that run at specific times. Rate expressions are simpler but less flexible than cron for calendar-based scheduling.

### Do I need aws_lambda_permission for every terraform lambda trigger?

**Yes, you must create an `aws_lambda_permission` resource for each service that invokes your Lambda.** Without this permission, CloudWatch Events (or EventBridge) cannot invoke the function due to AWS's resource-based policies. The `principal` must be `events.amazonaws.com` and the `source_arn` should reference your specific CloudWatch rule ARN to follow least-privilege security practices.

### How do I troubleshoot a terraform lambda trigger that isn't firing?

**First, verify the CloudWatch Events rule is enabled and the cron/rate expression is valid in the AWS Console.** Check CloudWatch Logs for the Lambda function to ensure it isn't erroring on invocation. Confirm the `aws_lambda_permission` resource exists with the correct `source_arn` matching the rule, as missing or incorrect permissions are the most common cause of silent trigger failures.

### Can I use terraform lambda triggers with Amazon EventBridge instead of CloudWatch Events?

**Yes, EventBridge uses the same underlying API as CloudWatch Events, so the `aws_cloudwatch_event_rule` and `aws_cloudwatch_event_target` resources work for both.** For EventBridge-specific features like event buses, use the `aws_cloudwatch_event_bus` resource and reference it in your rule's `event_bus_name` parameter. The permission structure remains identical, using `events.amazonaws.com` as the principal.