Terraform Actions vs Resource Actions

Terraform Actions vs Resource Actions

How does the new beta feature compare with AzAPI resource actions?

Terraform Actions vs Resource Actions

Terraform Actions, available in beta in Terraform v1.14, introduce a new way to perform operations outside the standard CRUD (Create-Read-Update-Delete) workflow on cloud resources.

Announced at HashiConf 2025, this feature allows you to define action blocks that can invoke functions, manage instance states, or perform other operations, either standalone or bound to resource lifecycles. This shifts some imperative tasks (previously handled by provisioners or external scripts) into Terraform’s declarative model.

For example, in AWS, you can invoke a Lambda function, stop an EC2 instance, or invalidate a CloudFront cache.

How does this compare to the AzAPI provider’s azapi_resource_action for Azure? At a high level, Terraform Actions are a high-level, provider-driven feature, whereas the AzAPI azapi_resource_action is a low-level, flexible, but more manual alternative for Azure.

Let’s explore with concrete examples.

AWS Examples from Terraform Actions

Mattias Fjellström’s Terraform Actions deep-dive blog provides AWS-focused examples using the AWS provider. Actions are defined in action blocks and can be triggered via CLI or resource lifecycles.

Invoking an AWS Lambda Function

1
2
3
4
5
6
7
8
action "aws_lambda_invoke" "message" {
  config {
    function_name = "send-a-message"
    payload       = jsonencode({
      message = "This is the action payload!"
    })
  }
}
  • Standalone Trigger: Run terraform apply -invoke=action.aws_lambda_invoke.message.
  • Lifecycle Binding: Attach to a resource’s lifecycle block to trigger after creation/update.

There are several examples in blog for the AWS cloud illustrating the power of chaining these actions together and using conditions, as well as other use cases such as cache invalidation.

Azure Example: Virtual Machine Power Action

Currently, the AzureRM provider only exposes the virtual_machine_power action (as far as I can tell), which supports start, stop, deallocate, and restart operations.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
action "azurerm_virtual_machine_power" "start_vm" {
  config {
    virtual_machine_id = azurerm_virtual_machine.example.id
    action             = "start" # one of: start | stop | deallocate | restart
  }
}

resource "azurerm_virtual_machine" "example" {
  # ... VM config ...

  lifecycle {
    action_trigger {
      events  = [after_create]
      actions = [action.azurerm_virtual_machine_power.start_vm]
    }
  }
}
  • Supported Actions: start, stop, deallocate, restart.
  • Standalone Trigger: terraform apply -invoke=action.azurerm_virtual_machine_power.start_vm.
  • Lifecycle Binding: As shown, triggers after VM creation (e.g., to ensure it’s running post-provisioning).

Comparison with AzAPI resource_action

AzAPI’s resource_action is a low-level alternative for Azure, let’s see how it compares:

Restarting a VM with AzAPI

1
2
3
4
5
6
resource "azapi_resource_action" "restart_vm" {
  type        = "Microsoft.Compute/virtualMachines@2025-04-01"
  resource_id = azurerm_virtual_machine.example.id
  action      = "restart"
  method      = "POST"
}
  • Flexibility: Works for any Azure API control plane action. Not only start, stop, deallocate, restart, you can also perform actions such as simulate eviction for Spot VMs.
  • No Built-in Lifecycle: i.e. you can simulate some lifecycle scenarios with replace_triggered_by, resource locks and explicit dependencies, but these are not event-phase hooks.
  • API Knowledge Required: You must know the type, action, and method from the Azure REST API.

Purging the cache with Azure Front Door

The code below illustrates how you can purge a Front Door cache - something currently not possible with Terraform Actions:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
resource "azapi_resource_action" "afd_purge" {
  type        = "Microsoft.Cdn/profiles/afdEndpoints@2025-04-15"
  resource_id = "/subscriptions/<subscription-id>/resourceGroups/<resource-group-name>/providers/Microsoft.Cdn/profiles/<profile-name>/afdEndpoints/<endpoint-name>"
  action      = "purge"
  method      = "POST"

  body = {
    contentPaths = [
      "/folder1"
    ]
    domains = [
      "blh-h4erdkahcrbte9hy.z03.azurefd.net"
    ]
  }

  response_export_values = ["*"]
}
Azure Front Door cache being purged

Invoke an Azure Function?

Is there an equivalent to invoking Lambda functions?

I don’t think this is possible with AzAPI, because the Function URL (invocation endpoint) is part of the data plane.

This is a general restriction with AzAPI, which targets (control plane) endpoints on management.azure.com with supported API versions; with minimal support for data plane operations.

If anyone reading this wishes to correct me, I’ll post an update!

What Can and Can’t You Do?

  • Terraform Actions (AWS/Azure):

    • Can Do: Declarative, lifecycle-bound operations for supported provider actions. Handles polling for long-running tasks. You can use action outputs to dynamically configure other resources. Actions appear in the terraform plan when triggered, making their execution predictable.
    • Can’t Do: Limited to actions implemented by the provider. At the time of writing, AzureRM has very little available, but in fairness, this has only just become available in beta.
  • AzAPI Resource Action:

    • Can Do: Initiate a REST API call to any Azure REST API action on the control plane, doesn’t require provider changes.
    • Can’t Do: Requires manual API details. No built-in lifecycle binding, and limited data plane support.

AzAPI resource actions are available now

If you’re on the Azure platform, and looking longingly at the actions capabilities, don’t forget your friendly AzAPI provider may provide the answer you need, today.

Future Outlook

A recent GitHub issue in the AzAPI provider repository (Azure/terraform-provider-azapi#988) requests support for Terraform Actions, including re-implementing azapi_resource_action as an action block and adding a generic action for any Azure data plane API.

I’m excited about this possibility - besides bringing AzAPI’s capabilities in Terraform closer to parity with AzureRM, it would open up a new world of possibility for the AzAPI provider in the data plane.

Refs

  1. https://mattias.engineer/blog/2025/terraform-actions-deep-dive/

  2. https://registry.terraform.io/providers/Azure/azapi/latest/docs/resources/resource_action

  3. https://developer.hashicorp.com/terraform/language/v1.14.x/invoke-actions

This post is licensed under CC BY 4.0 by the author.