terraform actions - I like hooks and I cannot lie

Declarative code is awesome and easy to write in most cases. It's decent because you don't need to think too much about state, deviation and how to realign operational with desired state.

In reality not everything is stateful, some things in life are just events that need to have something to happen - you could say event-driven. So, maybe IBM just prepares a tighter integration of two paradigms explicitly represented as ansible & terraform.

Luckily - terraform 1.14 beta brings events to terraform.

Let's start right away with some demo:

resource "azurerm_postgresql_flexible_server" "appdb" {
  name                   = var.server_name
  resource_group_name    = azurerm_resource_group.example.name
  location               = azurerm_resource_group.example.location
  version                = "17"
  administrator_login    = var.admin_username
  administrator_password = var.admin_password  
  # ..
  
  lifecycle {
    action_trigger {
      events = [after_create]
      actions = [
          action.aws_lambda_invoke.db_init, // Initialize the database
          action.ansible_playbook.application // Provision the server
      ]
    }
  }
}

action "ansible_playbook" "dbinit" {
  config {
    playbook_path = "${path.module}/dbinit.yml"
    host          = azurerm_postgresql_flexible_server.appdb.fqdn
    adminuser     = var.admin_username
    adminpassword = var.admin_password
  }
}

invoking an action after creation of a resource

This will invoke the dbinit playbook only after initial creation of the database. Clearly readable and easy to consume.

Why should this be relevant to me?

Think of the following use cases:

  • before_create
    On cloud providers you might need to do some REST API call to do an acceptance for some EULA whenever you use a given SKU the first time.
    You could aggregate requested SKUs, make a unique list, build some resource around them and invoke on before_create - exactly once.
  • after_create
    Assume you create some database and you have some database init script (like schema creations, core permission management etc.) which can't be represented as native terraform resources. You can just fire this through this action.
  • before_update
    Assume you want to do maybe some change on a resource - which possibly causes recreation, like kubernetes nodes/nodpeools, you could use this to actively drain those nodes (while considering your application specifics which might not be able to be reflected automatically).
  • after_update
    Maybe you do some helm deployments in kubernetes through terraform (if this is your taste - i won't judge :-)) and after the update you want to trigger a restart of pods (because this can't be done through helm approaches) - here you go.

Is this better than using script resources?

Actions represent a native way of hooking into the deployment process and react on some state changes. You can reach a similar behavior with null_resourcs - it just feels hacky and is sometimes nasty to control (while on the other hand sometimes you can be very explicit on what triggers the run).

resource "null_resource" "run_script" {
  triggers = {
    instance_id = aws_instance.example.id
  }

  provisioner "local-exec" {
    command = "bash /path/to/your/script.sh"
  }
}

using a nul_resource to run some script

Overall a decent new feature - be prepared for the release of terraform 1.14. If you want to get more about the background, check Daniel Schmidt's blog (one of the terraform engineers) here: https://danielmschmidt.de/posts/2025-09-26-terraform-actions-introduction/