Terraform
null_resource
local-exec
AWS CLI
infrastructure-as-code

Terraform, getting output from null_resource, local-exec and the AWS CLI

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

Introduction

Terraform users often try to capture command output from null_resource with local-exec, then discover that provisioners are poor data interfaces. local-exec is designed for side effects, not for feeding structured values into Terraform graph evaluation. For stable infrastructure code, provider-native data sources or external data sources are usually the correct path.

Core Sections

What null_resource and local-exec are good for

null_resource can run actions with provisioners, and local-exec runs shell commands on the machine executing Terraform. This is useful for notifications, bootstrap hooks, or local scripts that do not need to become Terraform state.

hcl
1resource "null_resource" "notify" {
2  provisioner "local-exec" {
3    command = "echo deployment complete"
4  }
5}

The command runs, but stdout is not exposed as typed Terraform attributes.

In newer Terraform versions, terraform_data is often a better fit than null_resource when you need a placeholder object for lifecycle wiring. Even then, the same rule applies: provisioners are for side effects, not for returning typed data back into the expression graph.

Why parsing local-exec output is brittle

Terraform plans resources declaratively. Provisioners run after resource creation and do not integrate cleanly with expression graph dependencies. Trying to parse command output for later resources creates hidden ordering and weak type guarantees.

Common issues:

  • command output format changes,
  • environment differences between local and CI,
  • partial failures leaving unclear state.

Prefer provider-native AWS data sources first

If AWS provider already exposes what you need, use it directly.

hcl
1data "aws_caller_identity" "current" {}
2
3data "aws_region" "current" {}
4
5output "account_id" {
6  value = data.aws_caller_identity.current.account_id
7}
8
9output "region" {
10  value = data.aws_region.current.name
11}

This keeps configuration typed, testable, and predictable.

Use external data source for custom command results

When provider data source is unavailable, use external with strict JSON output.

hcl
1data "external" "aws_identity" {
2  program = ["bash", "scripts/aws_identity.sh"]
3}
4
5output "arn" {
6  value = data.external.aws_identity.result.arn
7}

Example script:

bash
1#!/usr/bin/env bash
2set -euo pipefail
3
4ARN=$(aws sts get-caller-identity --query Arn --output text)
5ACCOUNT=$(aws sts get-caller-identity --query Account --output text)
6
7printf '{"arn":"%s","account":"%s"}\n' "$ARN" "$ACCOUNT"

Return only JSON object with string values unless your parser intentionally handles nested structures.

The important improvement over local-exec is timing. external runs as a data source, so Terraform can reason about its result during graph evaluation instead of treating command output as an after-the-fact side effect.

Keep ordering explicit with dependencies

If custom command depends on created resources, express dependency clearly instead of relying on side effects.

hcl
1data "external" "after_role" {
2  program    = ["bash", "scripts/check_role.sh"]
3  depends_on = [aws_iam_role.app_role]
4}

Explicit dependencies make plan behavior understandable for teammates and CI pipelines.

Handle authentication context consistently

AWS CLI output depends on credentials, profile, and region. A command that works locally may fail in CI due to missing role assumption or profile configuration.

Define one authentication strategy across environments and document it. For automation, prefer role-based ephemeral credentials over static keys.

Error handling and retry strategy

External scripts should fail fast with useful stderr when commands fail. For transient APIs, retries can be added carefully in script, but avoid masking persistent misconfiguration.

Never emit fake fallback JSON on failure unless you also signal failure clearly. Silent fallback creates dangerous misconfigurations.

Security considerations

Avoid exposing sensitive command outputs in Terraform outputs or logs. If values are sensitive, mark outputs as sensitive and limit log verbosity in CI.

hcl
1output "secret_value" {
2  value     = data.external.secret.result.token
3  sensitive = true
4}

Practical migration guideline

If current code relies heavily on null_resource output hacks, migrate incrementally:

  1. replace easy cases with provider data sources,
  2. move custom command output to external,
  3. remove redundant null resources,
  4. add CI checks for deterministic output.

This gives cleaner state and fewer surprise ordering bugs.

Common Pitfalls

  • Treating local-exec stdout as reliable Terraform data channel.
  • Using null_resource to model data dependencies instead of resources and data sources.
  • Returning non-JSON or inconsistent JSON from external scripts.
  • Ignoring AWS credential context differences between local and CI runs.
  • Logging sensitive command output in plain Terraform outputs.

Summary

  • Use local-exec for side effects, not structured Terraform values.
  • Prefer provider-native AWS data sources whenever possible.
  • Use external data source with strict JSON for custom data retrieval.
  • Keep dependencies and authentication explicit for reproducible behavior.
  • Reduce null_resource usage over time to improve maintainability and plan clarity.

Related reading
Course
Beginner
27 lessons
10 hours
System Design Fundamentals

Build a strong foundation in designing scalable, reliable distributed systems.

View the course
Track what you have practised

A free account saves your progress, solutions and study plan across every problem on Codemia.

System Design practice on Codemia

Work through 120+ system design problems with detailed solutions, from rate limiters to multi-region storage.

Practice system design

All Rights Reserved.