997 words
5 minutes

Leveraging null_resource in Terraform for Complex Operations

Cover image for Leveraging null_resource in Terraform for Complex Operations

Let’s not kid ourselves — null_resource is the duct tape of Terraform. It doesn’t provision a VM, it doesn’t configure a VPC, and it sure as hell doesn’t play nice with cloud-native best practices. But used wisely, it’s the unsung hero of CI/CD glue code and one-off automation.

In this post, we’ll get tactical with null_resource, walk through real-world use cases, and contrast it with the newer (and cleaner) terraform_data resource — so you know when to reach for which tool without feeling dirty.


Terraform Resources 101 (Quick Recap)#

Terraform’s core mechanic is the resource block — which tells the provider, “Hey, make this thing exist.”

resource "azurerm_windows_function_app" "app" {
name = "example-function-app"
location = "East US"
}

That’s your bread-and-butter declaration: define the desired state, let Terraform do the heavy lifting.

But sometimes, you don’t want to create anything in the cloud. You just want Terraform to do something — run a script, call a webhook, poke Jenkins with a stick. That’s where null_resource comes in.


What the Hell is null_resource?#

null_resource is exactly what it sounds like: a Terraform resource that manages nothing. No infrastructure, no API objects — just logic.

But here’s the trick: it still behaves like a real resource. It supports lifecycle actions (create, destroy, etc.), can depend on other resources, and — most importantly — supports provisioners and triggers.

resource "null_resource" "example" {
triggers = {
always_run = timestamp()
}
provisioner "local-exec" {
command = "echo 'Triggering follow-up actions'"
}
}

This block runs every time because the timestamp() changes on every plan. Perfect for when you need to kick off external processes after infra changes.


Triggers: The Secret Sauce#

Triggers are the magic behind null_resource. They control when it gets re-executed — not based on resource state, but on changes to arbitrary data.

Example:

triggers = {
hash = filemd5("config.json")
}

Now your null_resource only re-runs when config.json changes. This is gold in CI/CD setups where you’re tracking file changes, API responses, or even environment variables.


Real-World Scenarios (Where null_resource Actually Earns Its Keep)#

1. Post-Provision Webhook Pings#

Say you’ve just spun up infrastructure and need to notify an external system — like triggering a GitHub Actions workflow or pinging a Slack webhook.

resource "null_resource" "notify" {
triggers = {
infra_version = var.release_tag
}
provisioner "local-exec" {
command = "curl -X POST https://hooks.slack.com/services/XXX -d 'Terraform apply complete: ${var.release_tag}'"
}
}

Why not just use curl in your pipeline? Because this runs inside Terraform’s dependency graph — meaning it won’t fire unless upstream infra actually changed.

2. Conditional Execution Based on Dynamic Data#

Let’s say you’re pulling in an Azure storage account and want to trigger an action when its key changes.

data "azurerm_storage_account" "example" {
name = "examplestorageaccount"
resource_group_name = "my-rg"
}
resource "null_resource" "trigger_on_key_change" {
triggers = {
key = data.azurerm_storage_account.example.primary_access_key
}
provisioner "local-exec" {
command = "echo 'Access key has changed, executing...'"
}
}

This is ideal for invalidating cache, refreshing secrets, or kicking off a rotation script. And yes, it’s hacky — but it works.

3. Smoke Testing After Apply#

Spin up resources, run a curl test to confirm the service responds, fail fast if it doesn’t.

resource "null_resource" "smoke_test" {
depends_on = [azurerm_function_app.example]
provisioner "local-exec" {
command = "curl -sf http://example-app.azurewebsites.net/health || exit 1"
}
}

You’d be surprised how often infra “successfully applies” but the app is dead. This catches those cases before CI marks the job green.


The Cleaner Alternative: terraform_data (1.4+)#

Starting in Terraform 1.4, HashiCorp added a new built-in: terraform_data. It does what null_resource does — just with less baggage and without relying on a provider plugin.

resource "terraform_data" "run_command" {
provisioner "local-exec" {
command = "echo 'Still works!'"
}
}

You lose triggers (for now), but it’s first-party and cleaner for one-off tasks. Ideal for scripting or injecting data during apply without pretending to be a cloud resource.


null_resource vs terraform_data: When to Use What#

Use CaseUse null_resourceUse terraform_data
Triggering on external data changes
One-time scripting
CI/CD glue between real resources
Need clean, future-proof setup❌ (plugin)✅ (built-in)
Want something to break later

TL;DR: If you need triggers, stick with null_resource. Otherwise, migrate to terraform_data as the cleaner, future-proof alternative.


Final Thoughts#

If Terraform were a programming language, null_resource would be its eval() — powerful, dangerous, and misused 99% of the time.

But in the hands of someone who knows what they’re doing? It bridges the gap between infrastructure and orchestration — especially in CI/CD pipelines, edge cases, or situations where Terraform alone can’t model reality.

Just don’t go overboard. If you find yourself writing a bash script inside a null_resource that runs a Python script that generates more HCL… maybe reconsider your life choices.

Pro Tip: Pair null_resource with depends_on and triggers for controlled chaos. Or use terraform_data if you want to sleep at night.


Social Channels#


Community of IT Experts#


Is this content AI-generated?

No. Every article on this blog is written by me personally, drawing on decades of hands-on IT experience and a genuine passion for technology.

I use AI tools exclusively to help polish grammar and ensure my technical guidance is as clear as possible. However, the core ideas, strategic insights, and step-by-step solutions are entirely my own, born from real-world work.

Because of this human-and-AI partnership, some detection tools might flag this content. You can be confident, though, that the expertise is authentic. My goal is to share road-tested knowledge you can trust.

Leveraging null_resource in Terraform for Complex Operations
https://www.heyvaldemar.com/leveraging-null-resource-terraform-complex-operations/
Author
Vladimir Mikhalev
Published at
2024-05-04
License
CC BY-NC-SA 4.0